#include "PackManager.h" #include "PackProfile.h" #include "EterLib/BufferPool.h" #include #include #include #include #include "EterBase/Debug.h" CPackManager::CPackManager() : m_load_from_pack(true) , m_pBufferPool(nullptr) { m_pBufferPool = new CBufferPool(); } CPackManager::~CPackManager() { if (m_pBufferPool) { delete m_pBufferPool; m_pBufferPool = nullptr; } } bool CPackManager::AddPack(const std::string& path) { const std::filesystem::path packPath(path); if (packPath.extension() == ".m2p") { std::shared_ptr pack = std::make_shared(); const auto loadStart = std::chrono::steady_clock::now(); if (!pack->Load(path)) { RecordPackProfileMount( "m2p", path, false, 0, static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return false; } std::lock_guard lock(m_mutex); const auto& index = pack->GetIndex(); for (const auto& entry : index) { m_m2_entries[entry.path] = std::make_pair(pack, entry); } RecordPackProfileMount( "m2p", path, true, index.size(), static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return true; } std::shared_ptr pack = std::make_shared(); const auto loadStart = std::chrono::steady_clock::now(); if (!pack->Load(path)) { RecordPackProfileMount( "pck", path, false, 0, static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return false; } std::lock_guard lock(m_mutex); const auto& index = pack->GetIndex(); for (const auto& entry : index) { m_entries[entry.file_name] = std::make_pair(pack, entry); } RecordPackProfileMount( "pck", path, true, index.size(), static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return true; } bool CPackManager::GetFile(std::string_view path, TPackFile& result) { return GetFileWithPool(path, result, m_pBufferPool); } bool CPackManager::GetFileWithPool(std::string_view path, TPackFile& result, CBufferPool* pPool) { thread_local std::string buf; NormalizePath(path, buf); // First try to load from pack if (m_load_from_pack) { auto m2it = m_m2_entries.find(buf); if (m2it != m_m2_entries.end()) { const auto loadStart = std::chrono::steady_clock::now(); const bool ok = m2it->second.first->GetFileWithPool(m2it->second.second, result, pPool); RecordPackProfileLoad( "m2p", m2it->second.first->GetSourcePath(), buf, ok, ok ? result.size() : 0, static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return ok; } auto it = m_entries.find(buf); if (it != m_entries.end()) { const auto loadStart = std::chrono::steady_clock::now(); const bool ok = it->second.first->GetFileWithPool(it->second.second, result, pPool); RecordPackProfileLoad( "pck", it->second.first->GetSourcePath(), buf, ok, ok ? result.size() : 0, static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return ok; } } // Fallback to disk (for files not in packs, like bgm folder) const auto loadStart = std::chrono::steady_clock::now(); std::ifstream ifs(buf, std::ios::binary); if (ifs.is_open()) { ifs.seekg(0, std::ios::end); size_t size = ifs.tellg(); ifs.seekg(0, std::ios::beg); if (pPool) { result = pPool->Acquire(size); result.resize(size); } else { result.resize(size); } if (ifs.read((char*)result.data(), size)) { RecordPackProfileLoad( "disk", "", buf, true, result.size(), static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return true; } } RecordPackProfileLoad( "disk", "", buf, false, 0, static_cast(std::chrono::duration_cast( std::chrono::steady_clock::now() - loadStart).count())); return false; } bool CPackManager::IsExist(std::string_view path) const { thread_local std::string buf; NormalizePath(path, buf); // First check in pack entries if (m_load_from_pack) { auto m2it = m_m2_entries.find(buf); if (m2it != m_m2_entries.end()) { return true; } auto it = m_entries.find(buf); if (it != m_entries.end()) { return true; } } // Fallback to disk (for files not in packs, like bgm folder) std::error_code ec; // To avoid exceptions from std::filesystem const auto result = std::filesystem::exists(buf, ec); if (ec) { TraceError("std::filesystem::exists failed for path '%s' with error: %s", buf.c_str(), ec.message().c_str()); return false; } return result; } void CPackManager::NormalizePath(std::string_view in, std::string& out) const { out.resize(in.size()); for (std::size_t i = 0; i < out.size(); ++i) { if (in[i] == '\\') out[i] = '/'; else out[i] = static_cast(std::tolower(in[i])); } }