From bd28e4051fa5eb003c4a29366dd03c75eeeeb021 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 29 Dec 2022 01:43:52 -0800 Subject: [PATCH] Fix Hash Collisions in CDBehaviorParameter table (#930) * Fix hashing * Update CDBehaviorParameterTable.cpp --- dDatabase/Tables/CDBehaviorParameterTable.cpp | 41 ++++++++----------- dDatabase/Tables/CDBehaviorParameterTable.h | 12 +++--- dGame/dBehaviors/Behavior.cpp | 2 +- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index 96015896..d09a71b2 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -4,9 +4,9 @@ //! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); - size_t hash = 0; + uint32_t uniqueParameterId = 0; + uint64_t hash = 0; while (!tableData.eof()) { - hash = 0; CDBehaviorParameter entry; entry.behaviorID = tableData.getIntField(0, -1); auto candidateStringToAdd = std::string(tableData.getStringField(1, "")); @@ -14,15 +14,13 @@ CDBehaviorParameterTable::CDBehaviorParameterTable(void) { if (parameter != m_ParametersList.end()) { entry.parameterID = parameter; } else { - entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first; + entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first; + uniqueParameterId++; } + hash = entry.behaviorID; + hash = (hash << 31U) | entry.parameterID->second; entry.value = tableData.getFloatField(2, -1.0f); - GeneralUtils::hash_combine(hash, entry.behaviorID); - GeneralUtils::hash_combine(hash, *entry.parameterID); - - auto it = m_Entries.find(entry.behaviorID); - m_ParametersList.insert(*entry.parameterID); m_Entries.insert(std::make_pair(hash, entry)); tableData.nextRow(); @@ -38,31 +36,28 @@ std::string CDBehaviorParameterTable::GetName(void) const { return "BehaviorParameter"; } -CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) { - CDBehaviorParameter returnValue; - returnValue.behaviorID = 0; - returnValue.parameterID = m_ParametersList.end(); - returnValue.value = defaultValue; +float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { + auto parameterID = this->m_ParametersList.find(name); + if (parameterID == this->m_ParametersList.end()) return defaultValue; - size_t hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, name); + uint64_t hash = behaviorID; + + hash = (hash << 31U) | parameterID->second; // Search for specific parameter const auto& it = m_Entries.find(hash); - return it != m_Entries.end() ? it->second : returnValue; + return it != m_Entries.end() ? it->second.value : defaultValue; } std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { - size_t hash; + uint64_t hashBase = behaviorID; std::map returnInfo; - for (auto parameterCandidate : m_ParametersList) { - hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, parameterCandidate); + uint64_t hash; + for (auto& parameterCandidate : m_ParametersList) { + hash = (hashBase << 31U) | parameterCandidate.second; auto infoCandidate = m_Entries.find(hash); if (infoCandidate != m_Entries.end()) { - returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value)); + returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value)); } } return returnInfo; diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index f067e7d2..5d0d8b72 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -12,16 +12,16 @@ //! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::unordered_set::iterator parameterID; //!< The Parameter ID - float value; //!< The value of the behavior template + unsigned int behaviorID; //!< The Behavior ID + std::unordered_map::iterator parameterID; //!< The Parameter ID + float value; //!< The value of the behavior template }; //! BehaviorParameter table class CDBehaviorParameterTable : public CDTable { private: - std::unordered_map m_Entries; - std::unordered_set m_ParametersList; + std::unordered_map m_Entries; + std::unordered_map m_ParametersList; public: //! Constructor @@ -36,7 +36,7 @@ public: */ std::string GetName(void) const override; - CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); std::map GetParametersByBehaviorID(uint32_t behaviorID); }; diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 568780d0..40c37a95 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -439,7 +439,7 @@ Behavior::Behavior(const uint32_t behaviorId) { float Behavior::GetFloat(const std::string& name, const float defaultValue) const { // Get the behavior parameter entry and return its value. if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); - return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value; + return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue); }