Core: fixed realm first achievement

Porting of @shauren fix:
c75fcbe20b
This commit is contained in:
Yehonal
2017-10-17 00:28:01 +02:00
parent 7026d2e561
commit 76215c5c1f
2 changed files with 43 additions and 14 deletions

View File

@@ -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));

View File

@@ -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;