*Remove 'first_spell' and 'rank' columns from table spell_chain

*Separate req_spell and spell_chain data to save some memory
*Use spell_chain data generated from dbc instead of sql

--HG--
branch : trunk
This commit is contained in:
QAston
2008-12-22 02:11:11 +01:00
parent f91989cf64
commit e11dbbd62d
9 changed files with 218 additions and 163 deletions
+1 -1
View File
@@ -281,7 +281,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL },
{ "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
{ "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL },
{ "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL },
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
+1 -1
View File
@@ -248,7 +248,7 @@ class ChatHandler
bool HandleReloadSkillExtraItemTemplateCommand(const char* args);
bool HandleReloadSkillFishingBaseLevelCommand(const char* args);
bool HandleReloadSpellAffectCommand(const char* args);
bool HandleReloadSpellChainCommand(const char* args);
bool HandleReloadSpellRequiredCommand(const char* args);
bool HandleReloadSpellElixirCommand(const char* args);
bool HandleReloadSpellLearnSpellCommand(const char* args);
bool HandleReloadSpellProcEventCommand(const char* args);
+5 -5
View File
@@ -145,7 +145,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
HandleReloadSkillDiscoveryTemplateCommand("a");
HandleReloadSkillExtraItemTemplateCommand("a");
HandleReloadSpellAffectCommand("a");
HandleReloadSpellChainCommand("a");
HandleReloadSpellRequiredCommand("a");
HandleReloadSpellElixirCommand("a");
HandleReloadSpellLearnSpellCommand("a");
HandleReloadSpellProcEventCommand("a");
@@ -423,11 +423,11 @@ bool ChatHandler::HandleReloadSpellAffectCommand(const char*)
return true;
}
bool ChatHandler::HandleReloadSpellChainCommand(const char*)
bool ChatHandler::HandleReloadSpellRequiredCommand(const char*)
{
sLog.outString( "Re-Loading Spell Chain Data... " );
spellmgr.LoadSpellChains();
SendGlobalSysMessage("DB table `spell_chain` (spell ranks) reloaded.");
sLog.outString( "Re-Loading Spell Required Data... " );
spellmgr.LoadSpellRequired();
SendGlobalSysMessage("DB table `spell_required` reloaded.");
return true;
}
+3 -2
View File
@@ -174,6 +174,7 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell);
SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell);
uint32 req_spell = spellmgr.GetSpellRequired(tSpell->spell);
data << uint32(tSpell->spell);
data << uint8(_player->GetTrainerSpellState(tSpell));
@@ -184,8 +185,8 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
data << uint8(tSpell->reqlevel);
data << uint32(tSpell->reqskill);
data << uint32(tSpell->reqskillvalue);
data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
data << uint32(chain_node && chain_node->prev ? chain_node->req : 0);
data << uint32(chain_node && chain_node->prev ? chain_node->prev : req_spell);
data << uint32(chain_node && chain_node->prev ? req_spell : 0);
data << uint32(0);
}
+6 -3
View File
@@ -2952,8 +2952,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
removeSpell(node->next,disabled);
}
//unlearn spells dependent from recently removed spells
SpellRequiredMap const& reqMap = spellmgr.GetSpellRequiredMap();
SpellRequiredMap::const_iterator itr2 = reqMap.find(spell_id);
SpellsRequiringSpellMap const& reqMap = spellmgr.GetSpellsRequiringSpell();
SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id);
for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++)
removeSpell(itr2->second,disabled);
@@ -3546,9 +3546,12 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
// check prev.rank requirement
if(spell_chain->prev && !HasSpell(spell_chain->prev))
return TRAINER_SPELL_RED;
}
if(uint32 spell_req = spellmgr.GetSpellRequired(trainer_spell->spell))
{
// check additional spell requirement
if(spell_chain->req && !HasSpell(spell_chain->req))
if(!HasSpell(spell_req))
return TRAINER_SPELL_RED;
}
+177 -148
View File
@@ -1411,20 +1411,12 @@ SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spell
return NULL;
}
void SpellMgr::LoadSpellChains()
void SpellMgr::LoadSpellRequired()
{
mSpellChains.clear(); // need for reload case
mSpellReq.clear(); // need for reload case
mSpellsReqSpell.clear(); // need for reload case
mSpellReq.clear(); // need for reload case
QueryResult *result = WorldDatabase.Query("SELECT spell_id, first_spell, rank, req_spell from spell_chain ORDER BY first_spell, rank");
struct SpellChainEntry
{
uint32 spell;
uint32 first;
uint32 req;
uint8 rank;
};
QueryResult *result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
if(result == NULL)
{
@@ -1438,172 +1430,209 @@ void SpellMgr::LoadSpellChains()
}
uint32 rows = 0;
SpellChainEntry *SpellChainTable = new SpellChainEntry [result->GetRowCount()];
barGoLink bar( result->GetRowCount() );
do
{
bar.step();
Field *fields = result->Fetch();
SpellChainTable[rows].spell = fields[0].GetUInt32();
SpellChainTable[rows].first = fields[1].GetUInt32();
SpellChainTable[rows].rank = fields[2].GetUInt32();
SpellChainTable[rows].req = fields[3].GetUInt32();
if (SpellChainTable[rows].req)
mSpellReq.insert (std::pair<uint32, uint32>(SpellChainTable[rows].req, SpellChainTable[rows].spell));
uint32 spell_id = fields[0].GetUInt32();
uint32 spell_req = fields[1].GetUInt32();
mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
mSpellReq[spell_id] = spell_req;
++rows;
} while( result->NextRow() );
delete result;
uint32 cur_row=0;
do
sLog.outString();
sLog.outString( ">> Loaded %u spell required records", rows );
}
void SpellMgr::LoadSpellChains()
{
mSpellChains.clear(); // need for reload case
struct SpellRankEntry
{
uint32 spell_id=SpellChainTable[cur_row].spell;
SpellChainNode node;
node.first = SpellChainTable[cur_row].first;
node.rank = SpellChainTable[cur_row].rank;
node.req = SpellChainTable[cur_row].req;
uint32 SkillId;
char const *SpellName;
uint32 DurationIndex;
uint32 RangeIndex;
uint32 SpellVisual;
uint32 ProcFlags;
uint64 SpellFamilyFlags;
uint32 TargetAuraState;
uint32 ManaCost;
//get field "prev"
if (spell_id == node.first || cur_row==0)
{
if (node.rank!=1)
sLog.outErrorDb("Incorrect rank for entry: %u",spell_id);
node.prev = 0;
}
else if (SpellChainTable[cur_row-1].rank!=node.rank-1)
{
sLog.outErrorDb("Spells %u and %u (first: %u, rank: %d, req: %u) listed in `spell_chain` have not compatible rank data."
,spell_id,SpellChainTable[cur_row-1].spell,node.first,node.rank,node.req);
node.prev = 0;
}
else
node.prev=SpellChainTable[cur_row-1].spell;
//get field "next"
if (cur_row==rows-1 || SpellChainTable[cur_row+1].first!= node.first )
{
//get field "last"
for (uint32 last_row = 1; cur_row - last_row < rows && SpellChainTable[cur_row - last_row].first == node.first; ++last_row)
mSpellChains[SpellChainTable[cur_row-last_row].spell].last = spell_id;
node.last = spell_id;
node.next = 0;
}
else if (SpellChainTable[cur_row+1].rank!=node.rank+1)
{
sLog.outErrorDb("Spells %u and %u (first: %u, rank: %d, req: %u) listed in `spell_chain` have not compatible rank data."
,spell_id,SpellChainTable[cur_row+1].spell,node.first,node.rank,node.req);
node.next = 0;
}
else
{
node.next=SpellChainTable[cur_row+1].spell;
node.last=0;
}
cur_row++;
if(!sSpellStore.LookupEntry(spell_id))
{
sLog.outErrorDb("Spell %u listed in `spell_chain` does not exist",spell_id);
continue;
}
if(!sSpellStore.LookupEntry(node.first))
{
sLog.outErrorDb("Spell %u (first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing first rank spell.",
spell_id,node.first,node.rank,node.req);
continue;
}
if(node.req!=0 && !sSpellStore.LookupEntry(node.req))
{
sLog.outErrorDb("Spell %u (first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing required spell.",
spell_id,node.first,node.rank,node.req);
continue;
}
// talents not required data in spell chain for work, but must be checked if present for intergrity
if(TalentSpellPos const* pos = GetTalentSpellPos(spell_id))
{
if(node.rank!=pos->rank+1)
{
sLog.outErrorDb("Talent %u (first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong rank.",
spell_id,node.first,node.rank,node.req);
continue;
}
if(TalentEntry const* talentEntry = sTalentStore.LookupEntry(pos->talent_id))
{
if(node.first!=talentEntry->RankID[0])
{
sLog.outErrorDb("Talent %u (first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong first rank spell.",
spell_id,node.first,node.rank,node.req);
continue;
}
if(node.rank > 1 && node.prev != talentEntry->RankID[node.rank-1-1])
{
sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong prev rank spell.",
spell_id,node.prev,node.first,node.rank,node.req);
continue;
}
}
}
mSpellChains[spell_id] = node;
bool operator()(const SpellRankEntry & _Left,const SpellRankEntry & _Right)const
{
return (_Left.SkillId != _Right.SkillId ? _Left.SkillId < _Right.SkillId
: _Left.SpellName!=_Right.SpellName ? _Left.SpellName < _Right.SpellName
: _Left.ProcFlags!=_Right.ProcFlags ? _Left.ProcFlags < _Right.ProcFlags
: _Left.SpellFamilyFlags!=_Right.SpellFamilyFlags ? _Left.SpellFamilyFlags < _Right.SpellFamilyFlags
: (_Left.SpellVisual!=_Right.SpellVisual) && (!_Left.SpellVisual || !_Right.SpellVisual) ? _Left.SpellVisual < _Right.SpellVisual
: (_Left.ManaCost!=_Right.ManaCost) && (!_Left.ManaCost || !_Right.ManaCost) ? _Left.ManaCost < _Right.ManaCost
: (_Left.DurationIndex!=_Right.DurationIndex) && (!_Left.DurationIndex || !_Right.DurationIndex)? _Left.DurationIndex < _Right.DurationIndex
: (_Left.RangeIndex!=_Right.RangeIndex) && (!_Left.RangeIndex || !_Right.RangeIndex || _Left.RangeIndex==1 || !_Right.RangeIndex==1) ? _Left.RangeIndex < _Right.RangeIndex
: _Left.TargetAuraState < _Right.TargetAuraState
);
}
while( cur_row<rows );
delete[] SpellChainTable;
// additional integrity checks
for(SpellChainMap::iterator i = mSpellChains.begin(); i != mSpellChains.end(); ++i)
};
struct SpellRankValue
{
if(i->second.prev)
uint32 Id;
char const *Rank;
};
std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry> RankMap;
for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)
{
SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);
if (!AbilityInfo)
continue;
//get only spell with lowest ability_id to prevent doubles
uint32 spell_id=AbilityInfo->spellId;
if(mSkillLineAbilityMap.lower_bound(spell_id)->second->id!=ability_id)
continue;
SpellEntry const *SpellInfo=sSpellStore.LookupEntry(spell_id);
if (!SpellInfo)
continue;
std::string sRank = SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
if(sRank.empty())
continue;
SpellRankEntry entry;
SpellRankValue value;
entry.SkillId=AbilityInfo->skillId;
entry.SpellName=SpellInfo->SpellName[sWorld.GetDefaultDbcLocale()];
entry.DurationIndex=SpellInfo->DurationIndex;
entry.RangeIndex=SpellInfo->rangeIndex;
entry.ProcFlags=SpellInfo->procFlags;
entry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags;
entry.TargetAuraState=SpellInfo->TargetAuraState;
entry.SpellVisual=SpellInfo->SpellVisual;
entry.ManaCost=SpellInfo->manaCost;
value.Id=spell_id;
value.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(entry,value));
}
barGoLink bar(RankMap.size());
uint32 count=0;
for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr = RankMap.begin();itr!=RankMap.end();)
{
SpellRankEntry entry=itr->first;
//trac errors in extracted data
std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator> RankErrorMap;
for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
{
SpellChainMap::iterator i_prev = mSpellChains.find(i->second.prev);
if(i_prev == mSpellChains.end())
bar.step();
RankErrorMap.insert(std::pair<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>(itr2->second.Rank,itr2));
}
for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();)
{
char const * err_entry=itr2->first;
uint32 rank_count=RankErrorMap.count(itr2->first);
if (rank_count>1)
for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++)
{
sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found previous rank spell in table.",
i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id);
if (itr2->second->second.Id!=21084) //only one exception to these rules (not needed in 3.0.3)
{
sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id);
RankMap.erase(itr2->second);
itr=RankMap.lower_bound(entry);
}
}
else if( i_prev->second.first != i->second.first )
else
itr2++;
}
//do not proceed for spells with less than 2 ranks
uint32 spell_max_rank=RankMap.count(entry);
if (spell_max_rank<2)
{
itr=RankMap.upper_bound(entry);
continue;
}
itr=RankMap.upper_bound(entry);
//order spells by spells by spellLevel
std::list<uint32> RankedSpells;
uint32 min_spell_lvl=0;
std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator min_itr;
for (;RankMap.count(entry);)
{
for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
{
sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has different first spell in chain compared to previous rank spell (prev: %u, first: %u, rank: %d, req: %u).",
i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
SpellEntry const *SpellInfo=sSpellStore.LookupEntry(itr2->second.Id);
if (SpellInfo->spellLevel<min_spell_lvl || itr2==RankMap.lower_bound(entry))
{
min_spell_lvl=SpellInfo->spellLevel;
min_itr=itr2;
}
}
else if( i_prev->second.rank+1 != i->second.rank )
RankedSpells.push_back(min_itr->second.Id);
RankMap.erase(min_itr);
}
//use data from talent.dbc
uint16 talent_id=0;
for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();)
{
if (TalentSpellPos const* TalentPos=GetTalentSpellPos(*itr2))
{
sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has different rank compared to previous rank spell (prev: %u, first: %u, rank: %d, req: %u).",
i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
talent_id=TalentPos->talent_id;
RankedSpells.erase(itr2);
itr2 = RankedSpells.begin();
}
else
itr2++;
}
if (talent_id)
{
TalentEntry const *TalentInfo = sTalentStore.LookupEntry(talent_id);
for (uint8 rank=5;rank;rank--)
{
if (TalentInfo->RankID[rank-1])
RankedSpells.push_front(TalentInfo->RankID[rank-1]);
}
}
if(i->second.req)
count++;
itr=RankMap.upper_bound(entry);
uint32 spell_rank=1;
for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();spell_rank++)
{
SpellChainMap::iterator i_req = mSpellChains.find(i->second.req);
if(i_req == mSpellChains.end())
uint32 spell_id=*itr2;
mSpellChains[spell_id].rank=spell_rank;
mSpellChains[spell_id].first=RankedSpells.front();
mSpellChains[spell_id].last=RankedSpells.back();
itr2++;
if (spell_rank<2)
mSpellChains[spell_id].prev=0;
if (spell_id==RankedSpells.back())
mSpellChains[spell_id].next=0;
else
{
sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found required rank spell in table.",
i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
}
else if( i_req->second.first == i->second.first )
{
sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has required rank spell from same spell chain (prev: %u, first: %u, rank: %d, req: %u).",
i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
mSpellChains[*itr2].prev=spell_id;
mSpellChains[spell_id].next=*itr2;
}
}
}
sLog.outString();
sLog.outString( ">> Loaded %u spell chain records", rows );
sLog.outString( ">> Loaded %u spell chains",count);
}
void SpellMgr::LoadSpellLearnSkills()
+17 -3
View File
@@ -657,12 +657,15 @@ struct SpellChainNode
uint32 next;
uint32 first;
uint32 last;
uint32 req;
uint8 rank;
};
typedef UNORDERED_MAP<uint32, SpellChainNode> SpellChainMap;
typedef std::multimap<uint32, uint32> SpellRequiredMap;
// spell_id req_spell
typedef UNORDERED_MAP<uint32, uint32> SpellRequiredMap;
typedef std::multimap<uint32, uint32> SpellsRequiringSpellMap;
// Spell learning properties (accessed using SpellMgr functions)
struct SpellLearnSkillNode
@@ -787,6 +790,15 @@ class SpellMgr
return &itr->second;
}
uint32 GetSpellRequired(uint32 spell_id) const
{
SpellRequiredMap::const_iterator itr = mSpellReq.find(spell_id);
if(itr == mSpellReq.end())
return NULL;
return itr->second;
}
uint32 GetFirstSpellInChain(uint32 spell_id) const
{
if(SpellChainNode const* node = GetSpellChainNode(spell_id))
@@ -803,7 +815,7 @@ class SpellMgr
return 0;
}
SpellRequiredMap const& GetSpellRequiredMap() const { return mSpellReq; }
SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; }
// Note: not use rank for compare to spell ranks: spell chains isn't linear order
// Use IsHighRankOfSpell instead
@@ -947,6 +959,7 @@ class SpellMgr
// Loading data at server startup
void LoadSpellChains();
void LoadSpellRequired();
void LoadSpellLearnSkills();
void LoadSpellLearnSpells();
void LoadSpellScriptTarget();
@@ -963,6 +976,7 @@ class SpellMgr
private:
SpellScriptTarget mSpellScriptTarget;
SpellChainMap mSpellChains;
SpellsRequiringSpellMap mSpellsReqSpell;
SpellRequiredMap mSpellReq;
SpellLearnSkillMap mSpellLearnSkills;
SpellLearnSpellMap mSpellLearnSpells;
+3
View File
@@ -1091,6 +1091,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell Chain Data..." );
spellmgr.LoadSpellChains();
sLog.outString( "Loading Spell Required Data..." );
spellmgr.LoadSpellRequired();
sLog.outString( "Loading Spell Elixir types..." );
spellmgr.LoadSpellElixirs();