diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index c255bfb93..e4e26dec1 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -147,41 +147,97 @@ AchievementMgr::AchievementMgr(Player *player) AchievementMgr::~AchievementMgr() { - for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter) - delete iter->second; - m_criteriaProgress.clear(); } void AchievementMgr::SaveToDB() { if(!m_completedAchievements.empty()) { - CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE guid = %u", GetPlayer()->GetGUIDLow()); - - std::ostringstream ss; - ss << "INSERT INTO character_achievement (guid, achievement, date) VALUES "; + bool need_execute = false; + std::ostringstream ssdel; + std::ostringstream ssins; for(CompletedAchievementMap::iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); iter++) { - if(iter != m_completedAchievements.begin()) - ss << ", "; - ss << "("<GetGUIDLow() << ", " << iter->first << ", " << iter->second << ")"; + if(!iter->second.changed) + continue; + + /// first new/changed record prefix + if(!need_execute) + { + ssdel << "DELETE FROM character_achievement WHERE guid = " << GetPlayer()->GetGUIDLow() << " AND achievement IN ("; + ssins << "INSERT INTO character_achievement (guid, achievement, date) VALUES "; + need_execute = true; + } + /// next new/changed record prefix + else + { + ssdel << ", "; + ssins << ", "; + } + + // new/changed record data + ssdel << iter->first; + ssins << "("<GetGUIDLow() << ", " << iter->first << ", " << uint64(iter->second.date) << ")"; + + /// mark as saved in db + iter->second.changed = false; + } + + if(need_execute) + ssdel << ")"; + + if(need_execute) + { + CharacterDatabase.BeginTransaction (); + CharacterDatabase.Execute( ssdel.str().c_str() ); + CharacterDatabase.Execute( ssins.str().c_str() ); + CharacterDatabase.CommitTransaction (); } - CharacterDatabase.Execute( ss.str().c_str() ); } if(!m_criteriaProgress.empty()) { - CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = %u", GetPlayer()->GetGUIDLow()); - - std::ostringstream ss; - ss << "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES "; + /// prepare deleting and insert + bool need_execute = false; + std::ostringstream ssdel; + std::ostringstream ssins; for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter) { - if(iter != m_criteriaProgress.begin()) - ss << ", "; - ss << "(" << GetPlayer()->GetGUIDLow() << ", " << iter->first << ", " << iter->second->counter << ", " << iter->second->date << ")"; + if(!iter->second.changed) + continue; + + /// first new/changed record prefix + if(!need_execute) + { + ssdel << "DELETE FROM character_achievement_progress WHERE guid = " << GetPlayer()->GetGUIDLow() << " AND criteria IN ("; + ssins << "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES "; + need_execute = true; + } + /// next new/changed record prefix + else + { + ssdel << ", "; + ssins << ", "; + } + + // new/changed record data + ssdel << iter->first; + ssins << "(" << GetPlayer()->GetGUIDLow() << ", " << iter->first << ", " << iter->second.counter << ", " << iter->second.date << ")"; + + /// mark as saved in db + iter->second.changed = false; + } + + if(need_execute) + ssdel << ")"; + + if(need_execute) + { + CharacterDatabase.BeginTransaction (); + CharacterDatabase.Execute( ssdel.str().c_str() ); + CharacterDatabase.Execute( ssins.str().c_str() ); + CharacterDatabase.CommitTransaction (); } - CharacterDatabase.Execute( ss.str().c_str() ); } } @@ -192,7 +248,9 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri do { Field *fields = achievementResult->Fetch(); - m_completedAchievements[fields[0].GetUInt32()] = fields[1].GetUInt32(); + CompletedAchievementData& ca = m_completedAchievements[fields[0].GetUInt32()]; + ca.date = time_t(fields[1].GetUInt64()); + ca.changed = false; } while(achievementResult->NextRow()); delete achievementResult; } @@ -202,16 +260,19 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri do { Field *fields = criteriaResult->Fetch(); - CriteriaProgress *progress = new CriteriaProgress(fields[0].GetUInt32(), fields[1].GetUInt32(), fields[2].GetUInt64()); - AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(progress->id); - if(!criteria || - criteria->timeLimit && progress->date + criteria->timeLimit < time(NULL)) - { - delete progress; + uint32 id = fields[0].GetUInt32(); + uint32 counter = fields[1].GetUInt32(); + time_t date = time_t(fields[2].GetUInt64()); + + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(id); + if(!criteria || criteria->timeLimit && date + criteria->timeLimit < time(NULL)) continue; - } - m_criteriaProgress[progress->id] = progress; + + CriteriaProgress& progress = m_criteriaProgress[id]; + progress.counter = counter; + progress.date = date; + progress.changed = false; } while(criteriaResult->NextRow()); delete criteriaResult; } @@ -271,10 +332,10 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) GetPlayer()->SendMessageToSet(&data, true); } -void AchievementMgr::SendCriteriaUpdate(CriteriaProgress *progress) +void AchievementMgr::SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress) { WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8); - data << uint32(progress->id); + data << uint32(id); // the counter is packed like a packed Guid data.appendPackGUID(progress->counter); @@ -577,11 +638,11 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return false; } - CriteriaProgressMap::iterator itr = m_criteriaProgress.find(achievementCriteria->ID); + CriteriaProgressMap::const_iterator itr = m_criteriaProgress.find(achievementCriteria->ID); if(itr == m_criteriaProgress.end()) return false; - CriteriaProgress *progress = itr->second; + CriteriaProgress const* progress = &itr->second; switch(achievementCriteria->requiredType) { @@ -706,20 +767,26 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, sLog.outString("AchievementMgr::SetCriteriaProgress(%u, %u)", entry->ID, newValue); CriteriaProgress *progress = NULL; - if(m_criteriaProgress.find(entry->ID) == m_criteriaProgress.end()) + CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID); + + if(iter == m_criteriaProgress.end()) { - progress = new CriteriaProgress(entry->ID, newValue); - m_criteriaProgress[entry->ID]=progress; + progress = &m_criteriaProgress[entry->ID]; + progress->counter = 0; + progress->date = time(NULL); } else { - progress = m_criteriaProgress[entry->ID]; + progress = &iter->second; if(relative) newValue += progress->counter; if(progress->counter == newValue) return; progress->counter = newValue; } + + progress->changed = true; + if(entry->timeLimit) { time_t now = time(NULL); @@ -730,7 +797,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, // also it seems illogical, the timeframe will be extended at every criteria update progress->date = now; } - SendCriteriaUpdate(progress); + SendCriteriaUpdate(entry->ID,progress); } void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) @@ -740,7 +807,9 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) return; SendAchievementEarned(achievement); - m_completedAchievements[achievement->ID] = time(NULL); + CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; + ca.date = time(NULL); + ca.changed = true; // don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement // TODO: where do set this instead? @@ -819,20 +888,20 @@ void AchievementMgr::SendRespondInspectAchievements(Player* player) */ void AchievementMgr::BuildAllDataPacket(WorldPacket *data) { - for(CompletedAchievementMap::iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); ++iter) + for(CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); ++iter) { *data << uint32(iter->first); - *data << uint32(secsToTimeBitFields(iter->second)); + *data << uint32(secsToTimeBitFields(iter->second.date)); } *data << int32(-1); - for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter) + for(CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter) { - *data << uint32(iter->second->id); - data->appendPackGUID(iter->second->counter); + *data << uint32(iter->first); + data->appendPackGUID(iter->second.counter); data->append(GetPlayer()->GetPackGUID()); *data << uint32(0); - *data << uint32(secsToTimeBitFields(iter->second->date)); + *data << uint32(secsToTimeBitFields(iter->second.date)); *data << uint32(0); *data << uint32(0); } diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index 35e07570d..6392a9fc6 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -28,15 +28,9 @@ struct CriteriaProgress { - CriteriaProgress(uint32 id, uint32 counter, time_t date = time(NULL)) - { - this->id = id; - this->counter = counter; - this->date = date; - } - uint32 id; uint32 counter; time_t date; + bool changed; }; struct CriteriaCastSpellRequirement @@ -54,8 +48,14 @@ struct AchievementReward uint32 itemId; }; -typedef UNORDERED_MAP CriteriaProgressMap; -typedef UNORDERED_MAP CompletedAchievementMap; +struct CompletedAchievementData +{ + time_t date; + bool changed; +}; + +typedef UNORDERED_MAP CriteriaProgressMap; +typedef UNORDERED_MAP CompletedAchievementMap; class Unit; class Player; @@ -84,7 +84,7 @@ class AchievementMgr private: void SendAchievementEarned(AchievementEntry const* achievement); - void SendCriteriaUpdate(CriteriaProgress *progress); + void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress); void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 newValue, bool relative=false); void CompletedCriteria(AchievementCriteriaEntry const* entry); void CompletedAchievement(AchievementEntry const* entry); diff --git a/src/game/Player.h b/src/game/Player.h index 2682149f6..9035b0c8d 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -245,7 +245,7 @@ struct RuneInfo struct Runes { - RuneInfo runes[6]; + RuneInfo runes[MAX_RUNES]; uint8 runeState; // mask of available runes void SetRuneState(uint8 index, bool set = true) diff --git a/src/shared/Util.h b/src/shared/Util.h index 0b93cc985..e27d34efe 100644 --- a/src/shared/Util.h +++ b/src/shared/Util.h @@ -287,7 +287,7 @@ bool Utf8FitTo(std::string str, std::wstring search); #if PLATFORM == PLATFORM_WINDOWS #define UTF8PRINTF(OUT,FRM,RESERR) \ { \ - char temp_buf[6000]; \ + char temp_buf[32*1024]; \ va_list ap; \ va_start(ap, FRM); \ size_t temp_len = vsnprintf(temp_buf,6000,FRM,ap); \