Core: fixed realm first achievement
Porting of @shauren fix: https://github.com/TrinityCore/TrinityCore/commit/c75fcbe20b07fd7518be58bf02ba30d903133449
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
|
if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||||
// TODO: where do set this instead?
|
|
||||||
if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
|
||||||
sAchievementMgr->SetRealmCompleted(achievement);
|
sAchievementMgr->SetRealmCompleted(achievement);
|
||||||
|
|
||||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID);
|
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID);
|
||||||
@@ -2307,6 +2305,35 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
|
|||||||
return true;
|
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()
|
void AchievementGlobalMgr::LoadAchievementCriteriaList()
|
||||||
{
|
{
|
||||||
@@ -2628,6 +2655,14 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
|||||||
|
|
||||||
QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
|
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)
|
if (!result)
|
||||||
{
|
{
|
||||||
sLog->outString(">> Loaded 0 completed achievements. DB table `character_achievement` is empty.");
|
sLog->outString(">> Loaded 0 completed achievements. DB table `character_achievement` is empty.");
|
||||||
@@ -2655,7 +2690,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
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());
|
} while (result->NextRow());
|
||||||
|
|
||||||
sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
|
sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include <ace/Singleton.h>
|
#include <ace/Singleton.h>
|
||||||
@@ -348,15 +349,8 @@ class AchievementGlobalMgr
|
|||||||
return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
|
return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRealmCompleted(AchievementEntry const* achievement) const
|
bool IsRealmCompleted(AchievementEntry const* achievement) const;
|
||||||
{
|
void SetRealmCompleted(AchievementEntry const* achievement);
|
||||||
return m_allCompletedAchievements.find(achievement->ID) != m_allCompletedAchievements.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRealmCompleted(AchievementEntry const* achievement)
|
|
||||||
{
|
|
||||||
m_allCompletedAchievements.insert(achievement->ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadAchievementCriteriaList();
|
void LoadAchievementCriteriaList();
|
||||||
void LoadAchievementCriteriaData();
|
void LoadAchievementCriteriaData();
|
||||||
@@ -375,7 +369,7 @@ class AchievementGlobalMgr
|
|||||||
// store achievements by referenced achievement id to speed up lookup
|
// store achievements by referenced achievement id to speed up lookup
|
||||||
AchievementListByReferencedId m_AchievementListByReferencedId;
|
AchievementListByReferencedId m_AchievementListByReferencedId;
|
||||||
|
|
||||||
typedef std::set<uint32> AllCompletedAchievements;
|
typedef UNORDERED_MAP<uint32 /*achievementId*/, std::chrono::system_clock::time_point /*completionTime*/> AllCompletedAchievements;
|
||||||
AllCompletedAchievements m_allCompletedAchievements;
|
AllCompletedAchievements m_allCompletedAchievements;
|
||||||
|
|
||||||
AchievementRewards m_achievementRewards;
|
AchievementRewards m_achievementRewards;
|
||||||
|
|||||||
Reference in New Issue
Block a user