From d5624a8cddf239e42d536bc90150934feae0461d Mon Sep 17 00:00:00 2001 From: savis <106487343+savisxss@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:25:51 +0100 Subject: [PATCH] Add parallel race/motion loading and thread-safe Pack/Pool managers --- src/EterLib/Pool.h | 7 +++ src/GameLib/PropertyManager.cpp | 8 +++- src/GameLib/RaceData.h | 1 + src/GameLib/RaceManager.cpp | 80 ++++++++++++++++++++++++++------- src/PackLib/Pack.cpp | 10 ++--- src/PackLib/Pack.h | 7 ++- src/PackLib/PackManager.cpp | 13 +++++- 7 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/EterLib/Pool.h b/src/EterLib/Pool.h index 9d3f398..c7cafd7 100644 --- a/src/EterLib/Pool.h +++ b/src/EterLib/Pool.h @@ -1,6 +1,7 @@ #pragma once #include "EterBase/Debug.h" +#include template class CDynamicPool @@ -22,6 +23,7 @@ class CDynamicPool void Destroy() { + std::lock_guard lock(m_mutex); FreeAll(); for (T* p : m_Chunks) @@ -40,6 +42,7 @@ class CDynamicPool template T* Alloc(_Types&&... _Args) { + std::lock_guard lock(m_mutex); if (m_Free.empty()) Grow(); @@ -51,11 +54,13 @@ class CDynamicPool void Free(T* p) { p->~T(); + std::lock_guard lock(m_mutex); m_Free.push_back(p); } void FreeAll() { + std::lock_guard lock(m_mutex); for (T* p : m_Data) { if (std::find(m_Free.begin(), m_Free.end(), p) == m_Free.end()) { p->~T(); @@ -66,6 +71,7 @@ class CDynamicPool size_t GetCapacity() { + std::lock_guard lock(m_mutex); return m_Data.size(); } @@ -94,4 +100,5 @@ class CDynamicPool std::vector m_Free; std::vector m_Chunks; + std::recursive_mutex m_mutex; }; diff --git a/src/GameLib/PropertyManager.cpp b/src/GameLib/PropertyManager.cpp index e809030..65352ac 100644 --- a/src/GameLib/PropertyManager.cpp +++ b/src/GameLib/PropertyManager.cpp @@ -18,13 +18,19 @@ bool CPropertyManager::Initialize(const char * c_pszPackFileName) if (c_pszPackFileName) { m_pack = std::make_shared(); - if (!m_pack->Open(c_pszPackFileName, m_fileDict)) { + if (!m_pack->Load(c_pszPackFileName)) { LogBoxf("Cannot open property pack file (filename %s)", c_pszPackFileName); return false; } m_isFileMode = false; + const auto& index = m_pack->GetIndex(); + for (const auto& entry : index) + { + m_fileDict.emplace(entry.file_name, std::make_pair(m_pack, entry)); + } + for (auto it = m_fileDict.begin(); it != m_fileDict.end(); ++it) { std::string stFileName = it->second.second.file_name; if (!stricmp("property/reserve", stFileName.c_str())) { diff --git a/src/GameLib/RaceData.h b/src/GameLib/RaceData.h index 3df24a8..f37c593 100644 --- a/src/GameLib/RaceData.h +++ b/src/GameLib/RaceData.h @@ -137,6 +137,7 @@ class CRaceData void Destroy(); // Codes For Client + DWORD GetRaceIndex() const { return m_dwRaceIndex; } const char* GetBaseModelFileName() const; const char* GetAttributeFileName() const; const char* GetMotionListFileName() const; diff --git a/src/GameLib/RaceManager.cpp b/src/GameLib/RaceManager.cpp index 073e623..03ab625 100644 --- a/src/GameLib/RaceManager.cpp +++ b/src/GameLib/RaceManager.cpp @@ -2,6 +2,10 @@ #include "RaceManager.h" #include "RaceMotionData.h" #include "PackLib/PackManager.h" +#include +#include +#include +#include bool CRaceManager::s_bPreloaded = false; @@ -456,34 +460,54 @@ void CRaceManager::PreloadPlayerRaceMotions() if (s_bPreloaded) return; - // Preload all player races (0-7) + CRaceManager& rkRaceMgr = CRaceManager::Instance(); + + // Phase 1: Parallel Load Race Data (MSM) + std::vector> raceLoadFutures; + + for (DWORD dwRace = 0; dwRace <= 7; ++dwRace) + { + TRaceDataIterator it = rkRaceMgr.m_RaceDataMap.find(dwRace); + if (it == rkRaceMgr.m_RaceDataMap.end()) { + raceLoadFutures.push_back(std::async(std::launch::async, [&rkRaceMgr, dwRace]() { + return rkRaceMgr.__LoadRaceData(dwRace); + })); + } + } + + for (auto& f : raceLoadFutures) { + CRaceData* pRaceData = f.get(); + if (pRaceData) { + rkRaceMgr.m_RaceDataMap.insert(TRaceDataMap::value_type(pRaceData->GetRaceIndex(), pRaceData)); + } + } + + // Phase 2: Parallel Load Motions + std::set uniqueMotions; + for (DWORD dwRace = 0; dwRace <= 7; ++dwRace) { CRaceData* pRaceData = NULL; - if (!Instance().GetRaceDataPointer(dwRace, &pRaceData)) + TRaceDataIterator it = rkRaceMgr.m_RaceDataMap.find(dwRace); + if (it != rkRaceMgr.m_RaceDataMap.end()) + pRaceData = it->second; + + if (!pRaceData) continue; CRaceData::TMotionModeDataIterator itor; - if (pRaceData->CreateMotionModeIterator(itor)) { do { CRaceData::TMotionModeData* pMotionModeData = itor->second; - - CRaceData::TMotionVectorMap::iterator itorMotion = pMotionModeData->MotionVectorMap.begin(); - for (; itorMotion != pMotionModeData->MotionVectorMap.end(); ++itorMotion) + for (auto& itorMotion : pMotionModeData->MotionVectorMap) { - const CRaceData::TMotionVector& c_rMotionVector = itorMotion->second; - CRaceData::TMotionVector::const_iterator it; - - for (it = c_rMotionVector.begin(); it != c_rMotionVector.end(); ++it) + const CRaceData::TMotionVector& c_rMotionVector = itorMotion.second; + for (const auto& motion : c_rMotionVector) { - CGraphicThing* pMotion = it->pMotion; - if (pMotion) - { - pMotion->AddReference(); - } + if (motion.pMotion) + uniqueMotions.insert(motion.pMotion); } } } @@ -491,5 +515,31 @@ void CRaceManager::PreloadPlayerRaceMotions() } } + std::vector motionVec(uniqueMotions.begin(), uniqueMotions.end()); + size_t total = motionVec.size(); + + if (total > 0) { + size_t threadCount = std::thread::hardware_concurrency(); + if (threadCount == 0) threadCount = 4; + + size_t chunkSize = (total + threadCount - 1) / threadCount; + std::vector> motionFutures; + + for (size_t i = 0; i < threadCount; ++i) { + size_t start = i * chunkSize; + size_t end = std::min(start + chunkSize, total); + + if (start < end) { + motionFutures.push_back(std::async(std::launch::async, [start, end, &motionVec]() { + for (size_t k = start; k < end; ++k) { + motionVec[k]->AddReference(); + } + })); + } + } + + for (auto& f : motionFutures) f.get(); + } + s_bPreloaded = true; } diff --git a/src/PackLib/Pack.cpp b/src/PackLib/Pack.cpp index 93e0b42..307945b 100644 --- a/src/PackLib/Pack.cpp +++ b/src/PackLib/Pack.cpp @@ -13,7 +13,7 @@ static ZSTD_DCtx* GetThreadLocalZSTDContext() return g_zstdDCtx; } -bool CPack::Open(const std::string& path, TPackFileMap& entries) +bool CPack::Load(const std::string& path) { std::error_code ec; m_file.map(path, ec); @@ -34,13 +34,13 @@ bool CPack::Open(const std::string& path, TPackFileMap& entries) return false; } + m_index.resize(m_header.entry_num); + for (size_t i = 0; i < m_header.entry_num; i++) { - TPackFileEntry entry; + TPackFileEntry& entry = m_index[i]; memcpy(&entry, m_file.data() + sizeof(TPackFileHeader) + i * sizeof(TPackFileEntry), sizeof(TPackFileEntry)); m_decryption.ProcessData((CryptoPP::byte*)&entry, (CryptoPP::byte*)&entry, sizeof(TPackFileEntry)); - entries[entry.file_name] = std::make_pair(shared_from_this(), entry); - if (file_size < m_header.data_begin + entry.offset + entry.compressed_size) { return false; } @@ -97,4 +97,4 @@ bool CPack::GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBuf } return true; -} +} \ No newline at end of file diff --git a/src/PackLib/Pack.h b/src/PackLib/Pack.h index 24638fa..dfb12ac 100644 --- a/src/PackLib/Pack.h +++ b/src/PackLib/Pack.h @@ -12,13 +12,16 @@ public: CPack() = default; ~CPack() = default; - bool Open(const std::string& path, TPackFileMap& entries); + bool Load(const std::string& path); + const std::vector& GetIndex() const { return m_index; } + bool GetFile(const TPackFileEntry& entry, TPackFile& result); bool GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool); private: TPackFileHeader m_header; + std::vector m_index; mio::mmap_source m_file; CryptoPP::CTR_Mode::Decryption m_decryption; -}; \ No newline at end of file +}; diff --git a/src/PackLib/PackManager.cpp b/src/PackLib/PackManager.cpp index 8ad49af..bb2b6a8 100644 --- a/src/PackLib/PackManager.cpp +++ b/src/PackLib/PackManager.cpp @@ -23,8 +23,19 @@ bool CPackManager::AddPack(const std::string& path) { std::shared_ptr pack = std::make_shared(); + if (!pack->Load(path)) + { + return false; + } + std::lock_guard lock(m_mutex); - return pack->Open(path, m_entries); + const auto& index = pack->GetIndex(); + for (const auto& entry : index) + { + m_entries[entry.file_name] = std::make_pair(pack, entry); + } + + return true; } bool CPackManager::GetFile(std::string_view path, TPackFile& result)