Fix hash collisions in achievements (#962)

This commit is contained in:
David Markowitz 2023-01-21 07:37:09 -08:00 committed by GitHub
parent c8cd51ef63
commit cff94b6c22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 16 deletions

View File

@ -0,0 +1,43 @@
#ifndef __ACHIEVEMENTCACHEKEY__H__
#define __ACHIEVEMENTCACHEKEY__H__
class AchievementCacheKey {
public:
AchievementCacheKey() {
targets = "";
value = 0;
type = MissionTaskType::MISSION_TASK_TYPE_UNKNOWN;
};
bool operator==(const AchievementCacheKey& point) const {
return this->targets == point.targets && this->value == point.value && this->type == point.type;
};
void SetTargets(const std::string value) { this->targets = value; };
void SetValue(uint32_t value) { this->value = value; };
void SetType(MissionTaskType value) { this->type = value; };
std::string GetTargets() const { return this->targets; };
uint32_t GetValue() const { return this->value; };
MissionTaskType GetType() const { return this->type; };
private:
std::string targets;
uint32_t value;
MissionTaskType type;
};
// Specialization of hash for the above class
namespace std {
template<>
struct hash<AchievementCacheKey> {
size_t operator()(const AchievementCacheKey& key) const {
size_t hash = 0;
GeneralUtils::hash_combine(hash, key.GetType());
GeneralUtils::hash_combine(hash, key.GetValue());
GeneralUtils::hash_combine(hash, key.GetTargets());
return hash;
};
};
};
#endif //!__ACHIEVEMENTCACHEKEY__H__

View File

@ -17,10 +17,11 @@
#include "dZoneManager.h" #include "dZoneManager.h"
#include "Mail.h" #include "Mail.h"
#include "MissionPrerequisites.h" #include "MissionPrerequisites.h"
#include "AchievementCacheKey.h"
// MARK: Mission Component // MARK: Mission Component
std::unordered_map<size_t, std::vector<uint32_t>> MissionComponent::m_AchievementCache = {}; std::unordered_map<AchievementCacheKey, std::vector<uint32_t>> MissionComponent::m_AchievementCache = {};
//! Initializer //! Initializer
MissionComponent::MissionComponent(Entity* parent) : Component(parent) { MissionComponent::MissionComponent(Entity* parent) : Component(parent) {
@ -391,12 +392,12 @@ bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value,
const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType type, int32_t value, const std::string targets) { const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType type, int32_t value, const std::string targets) {
// Create a hash which represent this query for achievements // Create a hash which represent this query for achievements
size_t hash = 0; AchievementCacheKey toFind;
GeneralUtils::hash_combine(hash, type); toFind.SetType(type);
GeneralUtils::hash_combine(hash, value); toFind.SetValue(value);
GeneralUtils::hash_combine(hash, targets); toFind.SetTargets(targets);
const std::unordered_map<size_t, std::vector<uint32_t>>::iterator& iter = m_AchievementCache.find(hash); const auto& iter = m_AchievementCache.find(toFind);
// Check if this query is cached // Check if this query is cached
if (iter != m_AchievementCache.end()) { if (iter != m_AchievementCache.end()) {
@ -447,11 +448,9 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType
} }
} }
} }
// Insert into cache // Insert into cache
m_AchievementCache.insert_or_assign(hash, result); m_AchievementCache.insert_or_assign(toFind, result);
return m_AchievementCache.find(toFind)->second;
return m_AchievementCache.find(hash)->second;
} }
bool MissionComponent::RequiresItem(const LOT lot) { bool MissionComponent::RequiresItem(const LOT lot) {

View File

@ -17,11 +17,13 @@
#include "CDMissionsTable.h" #include "CDMissionsTable.h"
#include "Component.h" #include "Component.h"
/** class AchievementCacheKey;
* The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for
* progression of each of the mission task types (see MissionTaskType). /**
*/ * The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for
class MissionComponent : public Component * progression of each of the mission task types (see MissionTaskType).
*/
class MissionComponent: public Component
{ {
public: public:
static const uint32_t ComponentType = COMPONENT_TYPE_MISSION; static const uint32_t ComponentType = COMPONENT_TYPE_MISSION;
@ -192,7 +194,7 @@ private:
* As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a * As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a
* combination of tasks and values, so that they can be easily re-queried later * combination of tasks and values, so that they can be easily re-queried later
*/ */
static std::unordered_map<size_t, std::vector<uint32_t>> m_AchievementCache; static std::unordered_map<AchievementCacheKey, std::vector<uint32_t>> m_AchievementCache;
/** /**
* Order of missions in the UI. This value is incremented by 1 * Order of missions in the UI. This value is incremented by 1