Merge pull request #68 from savisxss/main
Add parallel race/motion loading and thread-safe Pack/Pool managers
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "EterBase/Debug.h"
|
#include "EterBase/Debug.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class CDynamicPool
|
class CDynamicPool
|
||||||
@@ -22,6 +23,7 @@ class CDynamicPool
|
|||||||
|
|
||||||
void Destroy()
|
void Destroy()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
FreeAll();
|
FreeAll();
|
||||||
|
|
||||||
for (T* p : m_Chunks)
|
for (T* p : m_Chunks)
|
||||||
@@ -40,6 +42,7 @@ class CDynamicPool
|
|||||||
template<class... _Types>
|
template<class... _Types>
|
||||||
T* Alloc(_Types&&... _Args)
|
T* Alloc(_Types&&... _Args)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
if (m_Free.empty())
|
if (m_Free.empty())
|
||||||
Grow();
|
Grow();
|
||||||
|
|
||||||
@@ -51,11 +54,13 @@ class CDynamicPool
|
|||||||
void Free(T* p)
|
void Free(T* p)
|
||||||
{
|
{
|
||||||
p->~T();
|
p->~T();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
m_Free.push_back(p);
|
m_Free.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeAll()
|
void FreeAll()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
for (T* p : m_Data) {
|
for (T* p : m_Data) {
|
||||||
if (std::find(m_Free.begin(), m_Free.end(), p) == m_Free.end()) {
|
if (std::find(m_Free.begin(), m_Free.end(), p) == m_Free.end()) {
|
||||||
p->~T();
|
p->~T();
|
||||||
@@ -66,6 +71,7 @@ class CDynamicPool
|
|||||||
|
|
||||||
size_t GetCapacity()
|
size_t GetCapacity()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
return m_Data.size();
|
return m_Data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,4 +100,5 @@ class CDynamicPool
|
|||||||
std::vector<T*> m_Free;
|
std::vector<T*> m_Free;
|
||||||
|
|
||||||
std::vector<T*> m_Chunks;
|
std::vector<T*> m_Chunks;
|
||||||
|
std::recursive_mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,13 +18,19 @@ bool CPropertyManager::Initialize(const char * c_pszPackFileName)
|
|||||||
if (c_pszPackFileName)
|
if (c_pszPackFileName)
|
||||||
{
|
{
|
||||||
m_pack = std::make_shared<CPack>();
|
m_pack = std::make_shared<CPack>();
|
||||||
if (!m_pack->Open(c_pszPackFileName, m_fileDict)) {
|
if (!m_pack->Load(c_pszPackFileName)) {
|
||||||
LogBoxf("Cannot open property pack file (filename %s)", c_pszPackFileName);
|
LogBoxf("Cannot open property pack file (filename %s)", c_pszPackFileName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_isFileMode = 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) {
|
for (auto it = m_fileDict.begin(); it != m_fileDict.end(); ++it) {
|
||||||
std::string stFileName = it->second.second.file_name;
|
std::string stFileName = it->second.second.file_name;
|
||||||
if (!stricmp("property/reserve", stFileName.c_str())) {
|
if (!stricmp("property/reserve", stFileName.c_str())) {
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ class CRaceData
|
|||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
// Codes For Client
|
// Codes For Client
|
||||||
|
DWORD GetRaceIndex() const { return m_dwRaceIndex; }
|
||||||
const char* GetBaseModelFileName() const;
|
const char* GetBaseModelFileName() const;
|
||||||
const char* GetAttributeFileName() const;
|
const char* GetAttributeFileName() const;
|
||||||
const char* GetMotionListFileName() const;
|
const char* GetMotionListFileName() const;
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
#include "RaceManager.h"
|
#include "RaceManager.h"
|
||||||
#include "RaceMotionData.h"
|
#include "RaceMotionData.h"
|
||||||
#include "PackLib/PackManager.h"
|
#include "PackLib/PackManager.h"
|
||||||
|
#include <future>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
bool CRaceManager::s_bPreloaded = false;
|
bool CRaceManager::s_bPreloaded = false;
|
||||||
|
|
||||||
@@ -456,34 +460,54 @@ void CRaceManager::PreloadPlayerRaceMotions()
|
|||||||
if (s_bPreloaded)
|
if (s_bPreloaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Preload all player races (0-7)
|
CRaceManager& rkRaceMgr = CRaceManager::Instance();
|
||||||
|
|
||||||
|
// Phase 1: Parallel Load Race Data (MSM)
|
||||||
|
std::vector<std::future<CRaceData*>> 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<CGraphicThing*> uniqueMotions;
|
||||||
|
|
||||||
for (DWORD dwRace = 0; dwRace <= 7; ++dwRace)
|
for (DWORD dwRace = 0; dwRace <= 7; ++dwRace)
|
||||||
{
|
{
|
||||||
CRaceData* pRaceData = NULL;
|
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;
|
continue;
|
||||||
|
|
||||||
CRaceData::TMotionModeDataIterator itor;
|
CRaceData::TMotionModeDataIterator itor;
|
||||||
|
|
||||||
if (pRaceData->CreateMotionModeIterator(itor))
|
if (pRaceData->CreateMotionModeIterator(itor))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
CRaceData::TMotionModeData* pMotionModeData = itor->second;
|
CRaceData::TMotionModeData* pMotionModeData = itor->second;
|
||||||
|
for (auto& itorMotion : pMotionModeData->MotionVectorMap)
|
||||||
CRaceData::TMotionVectorMap::iterator itorMotion = pMotionModeData->MotionVectorMap.begin();
|
|
||||||
for (; itorMotion != pMotionModeData->MotionVectorMap.end(); ++itorMotion)
|
|
||||||
{
|
{
|
||||||
const CRaceData::TMotionVector& c_rMotionVector = itorMotion->second;
|
const CRaceData::TMotionVector& c_rMotionVector = itorMotion.second;
|
||||||
CRaceData::TMotionVector::const_iterator it;
|
for (const auto& motion : c_rMotionVector)
|
||||||
|
|
||||||
for (it = c_rMotionVector.begin(); it != c_rMotionVector.end(); ++it)
|
|
||||||
{
|
{
|
||||||
CGraphicThing* pMotion = it->pMotion;
|
if (motion.pMotion)
|
||||||
if (pMotion)
|
uniqueMotions.insert(motion.pMotion);
|
||||||
{
|
|
||||||
pMotion->AddReference();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,5 +515,31 @@ void CRaceManager::PreloadPlayerRaceMotions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<CGraphicThing*> 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<std::future<void>> 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;
|
s_bPreloaded = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static ZSTD_DCtx* GetThreadLocalZSTDContext()
|
|||||||
return g_zstdDCtx;
|
return g_zstdDCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPack::Open(const std::string& path, TPackFileMap& entries)
|
bool CPack::Load(const std::string& path)
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
m_file.map(path, ec);
|
m_file.map(path, ec);
|
||||||
@@ -34,13 +34,13 @@ bool CPack::Open(const std::string& path, TPackFileMap& entries)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_index.resize(m_header.entry_num);
|
||||||
|
|
||||||
for (size_t i = 0; i < m_header.entry_num; i++) {
|
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));
|
memcpy(&entry, m_file.data() + sizeof(TPackFileHeader) + i * sizeof(TPackFileEntry), sizeof(TPackFileEntry));
|
||||||
m_decryption.ProcessData((CryptoPP::byte*)&entry, (CryptoPP::byte*)&entry, 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) {
|
if (file_size < m_header.data_begin + entry.offset + entry.compressed_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -97,4 +97,4 @@ bool CPack::GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBuf
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -12,13 +12,16 @@ public:
|
|||||||
CPack() = default;
|
CPack() = default;
|
||||||
~CPack() = default;
|
~CPack() = default;
|
||||||
|
|
||||||
bool Open(const std::string& path, TPackFileMap& entries);
|
bool Load(const std::string& path);
|
||||||
|
const std::vector<TPackFileEntry>& GetIndex() const { return m_index; }
|
||||||
|
|
||||||
bool GetFile(const TPackFileEntry& entry, TPackFile& result);
|
bool GetFile(const TPackFileEntry& entry, TPackFile& result);
|
||||||
bool GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool);
|
bool GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TPackFileHeader m_header;
|
TPackFileHeader m_header;
|
||||||
|
std::vector<TPackFileEntry> m_index;
|
||||||
mio::mmap_source m_file;
|
mio::mmap_source m_file;
|
||||||
|
|
||||||
CryptoPP::CTR_Mode<CryptoPP::Camellia>::Decryption m_decryption;
|
CryptoPP::CTR_Mode<CryptoPP::Camellia>::Decryption m_decryption;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,8 +23,19 @@ bool CPackManager::AddPack(const std::string& path)
|
|||||||
{
|
{
|
||||||
std::shared_ptr<CPack> pack = std::make_shared<CPack>();
|
std::shared_ptr<CPack> pack = std::make_shared<CPack>();
|
||||||
|
|
||||||
|
if (!pack->Load(path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
std::lock_guard<std::mutex> 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)
|
bool CPackManager::GetFile(std::string_view path, TPackFile& result)
|
||||||
|
|||||||
Reference in New Issue
Block a user