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 "Mail.h"
#include "MissionPrerequisites.h"
#include "AchievementCacheKey.h"
// 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
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) {
// Create a hash which represent this query for achievements
size_t hash = 0;
GeneralUtils::hash_combine(hash, type);
GeneralUtils::hash_combine(hash, value);
GeneralUtils::hash_combine(hash, targets);
AchievementCacheKey toFind;
toFind.SetType(type);
toFind.SetValue(value);
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
if (iter != m_AchievementCache.end()) {
@ -447,11 +448,9 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType
}
}
}
// Insert into cache
m_AchievementCache.insert_or_assign(hash, result);
return m_AchievementCache.find(hash)->second;
m_AchievementCache.insert_or_assign(toFind, result);
return m_AchievementCache.find(toFind)->second;
}
bool MissionComponent::RequiresItem(const LOT lot) {

View File

@ -17,11 +17,13 @@
#include "CDMissionsTable.h"
#include "Component.h"
/**
* 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).
*/
class MissionComponent : public Component
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).
*/
class MissionComponent: public Component
{
public:
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
* 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