mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 09:17:18 +00:00
Core: fixed realm first achievement
Porting of @shauren fix:
c75fcbe20b
This commit is contained in:
@@ -2163,9 +2163,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
|
||||
}
|
||||
}
|
||||
|
||||
// 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?
|
||||
if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
sAchievementMgr->SetRealmCompleted(achievement);
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID);
|
||||
@@ -2307,6 +2305,35 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
auto itr = m_allCompletedAchievements.find(achievement->ID);
|
||||
if (itr == m_allCompletedAchievements.end())
|
||||
return false;
|
||||
|
||||
if (itr->second == std::chrono::system_clock::time_point::min())
|
||||
return false;
|
||||
|
||||
if (itr->second == std::chrono::system_clock::time_point::max())
|
||||
return true;
|
||||
|
||||
// Allow completing the realm first kill for entire minute after first person did it
|
||||
// it may allow more than one group to achieve it (highly unlikely)
|
||||
// but apparently this is how blizz handles it as well
|
||||
if (achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
|
||||
return (std::chrono::system_clock::now() - itr->second) > std::chrono::minutes(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AchievementGlobalMgr::SetRealmCompleted(AchievementEntry const* achievement)
|
||||
{
|
||||
if (IsRealmCompleted(achievement))
|
||||
return;
|
||||
|
||||
m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
void AchievementGlobalMgr::LoadAchievementCriteriaList()
|
||||
{
|
||||
@@ -2628,6 +2655,14 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
|
||||
|
||||
// Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer
|
||||
// while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added
|
||||
// instead the only potential race will happen on value associated with the key
|
||||
for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
|
||||
if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
|
||||
if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::time_point::min();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 completed achievements. DB table `character_achievement` is empty.");
|
||||
@@ -2655,7 +2690,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
continue;
|
||||
}
|
||||
else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
m_allCompletedAchievements.insert(achievementId);
|
||||
m_allCompletedAchievements[achievementId] = std::chrono::system_clock::time_point::max();
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include "Common.h"
|
||||
#include <ace/Singleton.h>
|
||||
@@ -348,15 +349,8 @@ class AchievementGlobalMgr
|
||||
return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
|
||||
}
|
||||
|
||||
bool IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
return m_allCompletedAchievements.find(achievement->ID) != m_allCompletedAchievements.end();
|
||||
}
|
||||
|
||||
void SetRealmCompleted(AchievementEntry const* achievement)
|
||||
{
|
||||
m_allCompletedAchievements.insert(achievement->ID);
|
||||
}
|
||||
bool IsRealmCompleted(AchievementEntry const* achievement) const;
|
||||
void SetRealmCompleted(AchievementEntry const* achievement);
|
||||
|
||||
void LoadAchievementCriteriaList();
|
||||
void LoadAchievementCriteriaData();
|
||||
@@ -375,7 +369,7 @@ class AchievementGlobalMgr
|
||||
// store achievements by referenced achievement id to speed up lookup
|
||||
AchievementListByReferencedId m_AchievementListByReferencedId;
|
||||
|
||||
typedef std::set<uint32> AllCompletedAchievements;
|
||||
typedef UNORDERED_MAP<uint32 /*achievementId*/, std::chrono::system_clock::time_point /*completionTime*/> AllCompletedAchievements;
|
||||
AllCompletedAchievements m_allCompletedAchievements;
|
||||
|
||||
AchievementRewards m_achievementRewards;
|
||||
|
||||
Reference in New Issue
Block a user