mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-24 10:56:38 +01:00
Core/Spells: Automatically generate spell rank info from SkillLineAbility
* This fixes weird spellbook/talent/glyph/profession ui behavior when knowing multiple spells to remove talent or glyph, or multiple spells to open profession ui
This commit is contained in:
@@ -1261,113 +1261,76 @@ void SpellMgr::LoadSpellRanks()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, rank from spell_ranks ORDER BY first_spell_id, rank");
|
||||
|
||||
if (!result)
|
||||
std::map<uint32 /*spell*/, uint32 /*next*/> chains;
|
||||
std::set<uint32> hasPrev;
|
||||
for (SkillLineAbilityEntry const* skillAbility : sSkillLineAbilityStore)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 spell rank records. DB table `spell_ranks` is empty.");
|
||||
return;
|
||||
if (!skillAbility->SupercedesSpell)
|
||||
continue;
|
||||
|
||||
if (!GetSpellInfo(skillAbility->SupercedesSpell) || !GetSpellInfo(skillAbility->SpellID))
|
||||
continue;
|
||||
|
||||
chains[skillAbility->SupercedesSpell] = skillAbility->SpellID;
|
||||
hasPrev.insert(skillAbility->SpellID);
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
bool finished = false;
|
||||
|
||||
do
|
||||
// each key in chains that isn't present in hasPrev is a first rank
|
||||
for (auto itr = chains.begin(); itr != chains.end(); ++itr)
|
||||
{
|
||||
// spellid, rank
|
||||
std::list < std::pair < int32, int32 > > rankChain;
|
||||
int32 currentSpell = -1;
|
||||
int32 lastSpell = -1;
|
||||
|
||||
// fill one chain
|
||||
while (currentSpell == lastSpell && !finished)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
currentSpell = fields[0].GetUInt32();
|
||||
if (lastSpell == -1)
|
||||
lastSpell = currentSpell;
|
||||
uint32 spell_id = fields[1].GetUInt32();
|
||||
uint32 rank = fields[2].GetUInt8();
|
||||
|
||||
// don't drop the row if we're moving to the next rank
|
||||
if (currentSpell == lastSpell)
|
||||
{
|
||||
rankChain.push_back(std::make_pair(spell_id, rank));
|
||||
if (!result->NextRow())
|
||||
finished = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// check if chain is made with valid first spell
|
||||
SpellInfo const* first = GetSpellInfo(lastSpell);
|
||||
if (!first)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell);
|
||||
if (hasPrev.count(itr->first))
|
||||
continue;
|
||||
}
|
||||
// check if chain is long enough
|
||||
if (rankChain.size() < 2)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!", lastSpell);
|
||||
|
||||
SpellInfo const* first = GetSpellInfo(itr->first);
|
||||
SpellInfo const* next = GetSpellInfo(itr->second);
|
||||
|
||||
if (!first || next)
|
||||
continue;
|
||||
}
|
||||
int32 curRank = 0;
|
||||
bool valid = true;
|
||||
// check spells in chain
|
||||
for (std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); itr!= rankChain.end(); ++itr)
|
||||
|
||||
mSpellChains[itr->first].first = first;
|
||||
mSpellChains[itr->first].prev = nullptr;
|
||||
mSpellChains[itr->first].next = next;
|
||||
mSpellChains[itr->first].last = next;
|
||||
mSpellChains[itr->first].rank = 1;
|
||||
mSpellInfoMap[itr->first]->ChainEntry = &mSpellChains[itr->first];
|
||||
|
||||
mSpellChains[itr->second].first = first;
|
||||
mSpellChains[itr->second].prev = first;
|
||||
mSpellChains[itr->second].next = nullptr;
|
||||
mSpellChains[itr->second].last = next;
|
||||
mSpellChains[itr->second].rank = 2;
|
||||
mSpellInfoMap[itr->second]->ChainEntry = &mSpellChains[itr->second];
|
||||
|
||||
uint8 rank = 3;
|
||||
auto nextItr = chains.find(itr->second);
|
||||
while (nextItr != chains.end())
|
||||
{
|
||||
SpellInfo const* spell = GetSpellInfo(itr->first);
|
||||
if (!spell)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell);
|
||||
valid = false;
|
||||
SpellInfo const* prev = GetSpellInfo(nextItr->first); // already checked in previous iteration (or above, in case this is the first one)
|
||||
SpellInfo const* last = GetSpellInfo(nextItr->second);
|
||||
if (!last)
|
||||
break;
|
||||
}
|
||||
++curRank;
|
||||
if (itr->second != curRank)
|
||||
|
||||
mSpellChains[nextItr->first].next = last;
|
||||
|
||||
mSpellChains[nextItr->second].first = first;
|
||||
mSpellChains[nextItr->second].prev = prev;
|
||||
mSpellChains[nextItr->second].next = nullptr;
|
||||
mSpellChains[nextItr->second].last = last;
|
||||
mSpellChains[nextItr->second].rank = rank++;
|
||||
mSpellInfoMap[nextItr->second]->ChainEntry = &mSpellChains[nextItr->second];
|
||||
|
||||
// fill 'last'
|
||||
do
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not have a proper rank value (should be %u)!", itr->first, itr->second, lastSpell, curRank);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
mSpellChains[prev->Id].last = last;
|
||||
prev = mSpellChains[prev->Id].prev;
|
||||
} while (prev);
|
||||
|
||||
nextItr = chains.find(nextItr->second);
|
||||
}
|
||||
if (!valid)
|
||||
continue;
|
||||
int32 prevRank = 0;
|
||||
// insert the chain
|
||||
std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin();
|
||||
do
|
||||
{
|
||||
++count;
|
||||
int32 addedSpell = itr->first;
|
||||
|
||||
if (mSpellInfoMap[addedSpell]->ChainEntry)
|
||||
TC_LOG_ERROR("sql.sql", "The spell %u (rank: %u, first: %u) listed in `spell_ranks` already has ChainEntry from dbc.", addedSpell, itr->second, lastSpell);
|
||||
|
||||
mSpellChains[addedSpell].first = GetSpellInfo(lastSpell);
|
||||
mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first);
|
||||
mSpellChains[addedSpell].rank = itr->second;
|
||||
mSpellChains[addedSpell].prev = GetSpellInfo(prevRank);
|
||||
mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell];
|
||||
prevRank = addedSpell;
|
||||
++itr;
|
||||
|
||||
if (itr == rankChain.end())
|
||||
{
|
||||
mSpellChains[addedSpell].next = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
mSpellChains[addedSpell].next = GetSpellInfo(itr->first);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
while (!finished);
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", uint32(mSpellChains.size()), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellRequired()
|
||||
|
||||
Reference in New Issue
Block a user