diff --git a/include/pipeline/asset_manager.hpp b/include/pipeline/asset_manager.hpp index 4111e281..c3f0ce14 100644 --- a/include/pipeline/asset_manager.hpp +++ b/include/pipeline/asset_manager.hpp @@ -84,6 +84,13 @@ public: */ size_t getLoadedDBCCount() const { return dbcCache.size(); } + /** + * Get file cache stats + */ + size_t getFileCacheSize() const { return fileCacheTotalBytes; } + size_t getFileCacheHits() const { return fileCacheHits; } + size_t getFileCacheMisses() const { return fileCacheMisses; } + /** * Clear all cached resources */ @@ -97,6 +104,18 @@ private: mutable std::mutex readMutex; std::map> dbcCache; + // Decompressed file cache (LRU, 1GB budget for modern RAM) + struct CachedFile { + std::vector data; + uint64_t lastAccessTime; + }; + mutable std::map fileCache; + mutable size_t fileCacheTotalBytes = 0; + mutable uint64_t fileCacheAccessCounter = 0; + mutable size_t fileCacheHits = 0; + mutable size_t fileCacheMisses = 0; + static constexpr size_t FILE_CACHE_BUDGET = 1024 * 1024 * 1024; // 1GB + /** * Normalize path for case-insensitive lookup */ diff --git a/src/pipeline/asset_manager.cpp b/src/pipeline/asset_manager.cpp index ea12e8fa..f174e899 100644 --- a/src/pipeline/asset_manager.cpp +++ b/src/pipeline/asset_manager.cpp @@ -26,7 +26,7 @@ bool AssetManager::initialize(const std::string& dataPath_) { } initialized = true; - LOG_INFO("Asset manager initialized successfully"); + LOG_INFO("Asset manager initialized successfully (1GB file cache enabled)"); return true; } @@ -37,6 +37,13 @@ void AssetManager::shutdown() { LOG_INFO("Shutting down asset manager"); + // Log cache statistics + if (fileCacheHits + fileCacheMisses > 0) { + float hitRate = (float)fileCacheHits / (fileCacheHits + fileCacheMisses) * 100.0f; + LOG_INFO("File cache stats: ", fileCacheHits, " hits, ", fileCacheMisses, " misses (", + (int)hitRate, "% hit rate), ", fileCacheTotalBytes / 1024 / 1024, " MB cached"); + } + clearCache(); mpqManager.shutdown(); @@ -141,13 +148,59 @@ std::vector AssetManager::readFile(const std::string& path) const { return std::vector(); } + std::string normalized = normalizePath(path); std::lock_guard lock(readMutex); - return mpqManager.readFile(normalizePath(path)); + + // Check cache first + auto it = fileCache.find(normalized); + if (it != fileCache.end()) { + // Cache hit - update access time and return cached data + it->second.lastAccessTime = ++fileCacheAccessCounter; + fileCacheHits++; + return it->second.data; + } + + // Cache miss - decompress from MPQ + fileCacheMisses++; + std::vector data = mpqManager.readFile(normalized); + if (data.empty()) { + return data; // File not found + } + + // Add to cache if within budget + size_t fileSize = data.size(); + if (fileSize > 0 && fileSize < FILE_CACHE_BUDGET / 10) { // Don't cache files > 100MB + // Evict old entries if needed (LRU) + while (fileCacheTotalBytes + fileSize > FILE_CACHE_BUDGET && !fileCache.empty()) { + // Find least recently used entry + auto lru = fileCache.begin(); + for (auto it = fileCache.begin(); it != fileCache.end(); ++it) { + if (it->second.lastAccessTime < lru->second.lastAccessTime) { + lru = it; + } + } + fileCacheTotalBytes -= lru->second.data.size(); + fileCache.erase(lru); + } + + // Add new entry + CachedFile cached; + cached.data = data; + cached.lastAccessTime = ++fileCacheAccessCounter; + fileCache[normalized] = std::move(cached); + fileCacheTotalBytes += fileSize; + } + + return data; } void AssetManager::clearCache() { + std::lock_guard lock(readMutex); dbcCache.clear(); - LOG_INFO("Cleared asset cache"); + fileCache.clear(); + fileCacheTotalBytes = 0; + fileCacheAccessCounter = 0; + LOG_INFO("Cleared asset cache (DBC + file cache)"); } std::string AssetManager::normalizePath(const std::string& path) const {