From 34fa43ed9381b6a1ef6d6c83e46800ee81426f53 Mon Sep 17 00:00:00 2001 From: wincent Date: Sat, 9 Jul 2022 22:59:36 +0200 Subject: [PATCH] Initial concept for CDClient rework. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilizes `boost::interprocess` to share a map between worlds. The master server loads the table into memory, and the worlds hook into it when they want to get an entry. This solves the issue of skill delay, but introduces the third-party library Boost. There should be a conversation about the introduction of Boost — it is a large library and adds extra steps to the installation. --- CMakeLists.txt | 9 ++ dDatabase/Tables/CDBehaviorParameterTable.cpp | 125 +++++++++++++----- dDatabase/Tables/CDBehaviorParameterTable.h | 12 +- dGame/dBehaviors/AndBehavior.cpp | 20 ++- dGame/dBehaviors/Behavior.cpp | 6 +- dGame/dBehaviors/ChainBehavior.cpp | 18 ++- dGame/dBehaviors/NpcCombatSkillBehavior.cpp | 18 ++- dMasterServer/MasterServer.cpp | 2 + 8 files changed, 143 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cf311d2..47882b24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,15 @@ target_link_libraries(dNet dDatabase) target_link_libraries(dGame dDatabase) target_link_libraries(dChatFilter dDatabase) +# Include Boost +find_package(Boost COMPONENTS interprocess) + +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + + target_link_libraries(dGame ${Boost_LIBRARIES}) +endif() + if(WIN32) target_link_libraries(raknet ws2_32) endif(WIN32) diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index bbbdb2b6..d59f868f 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -1,27 +1,35 @@ #include "CDBehaviorParameterTable.h" #include "GeneralUtils.h" +#include "Game.h" +#include "dLogger.h" +#include "dServer.h" + +#include +#include +#include +#include +#include +#include + +typedef size_t KeyType; +typedef float MappedType; +typedef std::pair ValueType; + +typedef boost::interprocess::allocator ShmemAllocator; + +typedef boost::interprocess::map, ShmemAllocator> CDBehaviorParameterMap; + +CDBehaviorParameterMap *table = nullptr; + +CppSQLite3Statement preparedStatementSingle; +CppSQLite3Statement preparedStatementMultiple; + +//#define CACHE_ALL_BEHAVIORS + //! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); - size_t hash = 0; - while (!tableData.eof()) { - hash = 0; - CDBehaviorParameter entry; - entry.behaviorID = tableData.getIntField(0, -1); - entry.parameterID = tableData.getStringField(1, ""); - 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(); - } - tableData.finalize(); } //! Destructor @@ -32,33 +40,78 @@ std::string CDBehaviorParameterTable::GetName(void) const { return "BehaviorParameter"; } -CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) +float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) { - CDBehaviorParameter returnValue; - returnValue.behaviorID = 0; - returnValue.parameterID = ""; - returnValue.value = defaultValue; - size_t hash = 0; GeneralUtils::hash_combine(hash, behaviorID); GeneralUtils::hash_combine(hash, name); // Search for specific parameter - const auto& it = m_Entries.find(hash); - return it != m_Entries.end() ? it->second : returnValue; + try { + boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "CDBehaviorParameterTable"); + + // If the segment manager is not null, then the segment exists + // Get the table from the segment + ShmemAllocator alloc_inst (segment.get_segment_manager()); + + boost::interprocess::offset_ptr m = segment.find("CDBehaviorParameter").first; + + if (m == nullptr) { + Game::logger->Log("CDBehaviorParameterTable", "CDBehaviorParameter segment is nullptr!\n"); + + return defaultValue; + } + + auto it = m->find(hash); + + if (it != m->end()) { + return it->second; + } + + return defaultValue; + } + catch (std::exception &e) { + Game::logger->Log("CDBehaviorParameterTable", "Failed to find entry for behaviorID: %d, parameterID: %s\n%e\n", behaviorID, name.c_str(), e.what()); + + return defaultValue; + } } -std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { - size_t hash; - std::map returnInfo; - for (auto parameterCandidate : m_ParametersList) { +void CDBehaviorParameterTable::CreateSharedMap() +{ + boost::interprocess::shared_memory_object::remove("CDBehaviorParameterTable"); + + Game::logger->Log("CDBehaviorParameterTable", "Failed to open or create shared memory segment, creating...\n"); + + // If the segment manager is null, then the segment does not exist + // Create the segment + boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "CDBehaviorParameterTable", 40 * 1000 * 1000); + + ShmemAllocator alloc_inst (segment.get_segment_manager()); + + table = segment.construct("CDBehaviorParameter") //object name + (std::less() //first ctor parameter + ,alloc_inst); //second ctor parameter + + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); + + size_t hash = 0; + + while (!tableData.eof()) { hash = 0; + + int32_t behaviorID = tableData.getIntField(0, -1); + std::string parameterID = tableData.getStringField(1, ""); + GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, parameterCandidate); - auto infoCandidate = m_Entries.find(hash); - if (infoCandidate != m_Entries.end()) { - returnInfo.insert(std::make_pair(infoCandidate->second.parameterID, infoCandidate->second.value)); - } + GeneralUtils::hash_combine(hash, parameterID); + + float value = tableData.getFloatField(2, -1.0f); + + table->insert(ValueType(hash, value)); + + tableData.nextRow(); } - return returnInfo; + + tableData.finalize(); } diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index 17605636..fd09e10c 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -12,17 +12,17 @@ //! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::string parameterID; //!< The Parameter ID + int32_t behaviorID; //!< The Behavior ID + int32_t 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; public: + static void CreateSharedMap(); //! Constructor CDBehaviorParameterTable(void); @@ -36,7 +36,5 @@ public: */ std::string GetName(void) const override; - CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); - - std::map GetParametersByBehaviorID(uint32_t behaviorID); + float GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); }; diff --git a/dGame/dBehaviors/AndBehavior.cpp b/dGame/dBehaviors/AndBehavior.cpp index 5fc1e113..60597d42 100644 --- a/dGame/dBehaviors/AndBehavior.cpp +++ b/dGame/dBehaviors/AndBehavior.cpp @@ -3,6 +3,8 @@ #include "Game.h" #include "dLogger.h" +#include + void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { for (auto* behavior : this->m_behaviors) @@ -27,15 +29,19 @@ void AndBehavior::UnCast(BehaviorContext* context, const BehaviorBranchContext b void AndBehavior::Load() { - const auto parameters = GetParameterNames(); + std::string ss = "behavior "; - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { - auto* action = GetAction(parameter.second); + int i = 1; - this->m_behaviors.push_back(action); + while (true) { + std::string s = ss + std::to_string(i); + + if (GetInt(s, 0) == 0) { + break; } + + m_behaviors.push_back(GetAction(s)); + + ++i; } } diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index ac1ab7de..7f84c597 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -453,7 +453,7 @@ float Behavior::GetFloat(const std::string& name, const float defaultValue) cons { // 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->GetEntry(this->m_behaviorId, name, defaultValue); } @@ -485,10 +485,10 @@ std::map Behavior::GetParameterNames() const { std::map templatesInDatabase; // Find behavior template by its behavior id. - if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); + /*if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); if (BehaviorParameterTable) { templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(this->m_behaviorId); - } + }*/ return templatesInDatabase; } diff --git a/dGame/dBehaviors/ChainBehavior.cpp b/dGame/dBehaviors/ChainBehavior.cpp index 0d49de82..230f33a0 100644 --- a/dGame/dBehaviors/ChainBehavior.cpp +++ b/dGame/dBehaviors/ChainBehavior.cpp @@ -26,15 +26,19 @@ void ChainBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt void ChainBehavior::Load() { - const auto parameters = GetParameterNames(); + std::string ss = "behavior "; - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { - auto* action = GetAction(parameter.second); + int i = 1; - this->m_behaviors.push_back(action); + while (true) { + std::string s = ss + std::to_string(i); + + if (GetInt(s, 0) == 0) { + break; } + + m_behaviors.push_back(GetAction(s)); + + ++i; } } diff --git a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp index c2aff256..8eb85507 100644 --- a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp +++ b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp @@ -17,15 +17,19 @@ void NpcCombatSkillBehavior::Load() { this->m_npcSkillTime = GetFloat("npc skill time"); - const auto parameters = GetParameterNames(); + std::string ss = "behavior "; - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { - auto* action = GetAction(parameter.second); + int i = 1; - this->m_behaviors.push_back(action); + while (true) { + std::string s = ss + std::to_string(i); + + if (GetInt(s, 0) == 0) { + break; } + + m_behaviors.push_back(GetAction(s)); + + ++i; } } diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index ac49b1a1..e3a8e411 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -218,6 +218,8 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(Game::logger); Game::im = new InstanceManager(Game::logger, Game::server->GetIP()); + CDBehaviorParameterTable::CreateSharedMap(); + //Depending on the config, start up servers: if (config.GetValue("prestart_servers") != "" && config.GetValue("prestart_servers") == "1") { StartChatServer();