From 19652ae521dda2e9b98d1a503772e6c8e69282ad Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 28 Feb 2026 09:07:47 -0800 Subject: [PATCH] Add purgeExtractedAssets() to clear all extracted asset data from disk --- include/pipeline/asset_manager.hpp | 9 ++ src/pipeline/asset_manager.cpp | 128 +++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/include/pipeline/asset_manager.hpp b/include/pipeline/asset_manager.hpp index 2f444b16..a32895d6 100644 --- a/include/pipeline/asset_manager.hpp +++ b/include/pipeline/asset_manager.hpp @@ -117,6 +117,15 @@ public: */ void clearDBCCache(); + /** + * Delete all extracted asset files from the data directory on disk. + * Removes extracted subdirectories (db, character, creature, terrain, etc.), + * manifest.json, override dir, and expansion-specific extracted assets. + * After calling this, initialize() will fail until assets are re-extracted. + * @return Number of entries removed + */ + size_t purgeExtractedAssets(); + private: bool initialized = false; std::string dataPath; diff --git a/src/pipeline/asset_manager.cpp b/src/pipeline/asset_manager.cpp index 9f0cfaea..19fa13f8 100644 --- a/src/pipeline/asset_manager.cpp +++ b/src/pipeline/asset_manager.cpp @@ -393,6 +393,134 @@ void AssetManager::clearCache() { LOG_INFO("Cleared asset cache (DBC + file cache)"); } +size_t AssetManager::purgeExtractedAssets() { + clearCache(); + + if (dataPath.empty()) { + LOG_WARNING("Cannot purge: no data path set"); + return 0; + } + + size_t removed = 0; + namespace fs = std::filesystem; + + // Extracted MPQ content directories + const char* extractedDirs[] = { + "db", "character", "creature", "terrain", "world", + "interface", "item", "sound", "spell", "environment", + "misc", "enUS", + // Case variants (Windows-extracted assets) + "Character", "Creature", "World" + }; + + for (const auto& dir : extractedDirs) { + fs::path p = fs::path(dataPath) / dir; + if (fs::exists(p)) { + std::error_code ec; + auto count = fs::remove_all(p, ec); + if (!ec) { + LOG_INFO("Purged: ", p.string(), " (", count, " entries)"); + removed += count; + } else { + LOG_WARNING("Failed to remove ", p.string(), ": ", ec.message()); + } + } + } + + // Root manifest + fs::path manifestPath = fs::path(dataPath) / "manifest.json"; + if (fs::exists(manifestPath)) { + std::error_code ec; + fs::remove(manifestPath, ec); + if (!ec) { + LOG_INFO("Purged: ", manifestPath.string()); + ++removed; + } + } + + // Override directory + if (!overridePath_.empty() && fs::exists(overridePath_)) { + std::error_code ec; + auto count = fs::remove_all(overridePath_, ec); + if (!ec) { + LOG_INFO("Purged: ", overridePath_, " (", count, " entries)"); + removed += count; + } + } + + // HD texture packs + fs::path hdPath = fs::path(dataPath) / "hd"; + if (fs::exists(hdPath)) { + std::error_code ec; + auto count = fs::remove_all(hdPath, ec); + if (!ec) { + LOG_INFO("Purged: ", hdPath.string(), " (", count, " entries)"); + removed += count; + } + } + + // Per-expansion extracted assets, manifests, and overlays + fs::path expansionsDir = fs::path(dataPath) / "expansions"; + if (fs::is_directory(expansionsDir)) { + for (auto& expEntry : fs::directory_iterator(expansionsDir)) { + if (!expEntry.is_directory()) continue; + fs::path expDir = expEntry.path(); + + // Extracted assets + fs::path assetsDir = expDir / "assets"; + if (fs::exists(assetsDir)) { + std::error_code ec; + auto count = fs::remove_all(assetsDir, ec); + if (!ec) { + LOG_INFO("Purged: ", assetsDir.string(), " (", count, " entries)"); + removed += count; + } + } + + // Expansion manifest + fs::path expManifest = expDir / "manifest.json"; + if (fs::exists(expManifest)) { + std::error_code ec; + fs::remove(expManifest, ec); + if (!ec) { + LOG_INFO("Purged: ", expManifest.string()); + ++removed; + } + } + + // Overlay + fs::path overlayDir = expDir / "overlay"; + if (fs::exists(overlayDir)) { + std::error_code ec; + auto count = fs::remove_all(overlayDir, ec); + if (!ec) { + LOG_INFO("Purged: ", overlayDir.string(), " (", count, " entries)"); + removed += count; + } + } + + // Generated CSVs + fs::path dbDir = expDir / "db"; + if (fs::is_directory(dbDir)) { + for (auto& f : fs::directory_iterator(dbDir)) { + if (f.path().extension() == ".csv") { + std::error_code ec; + fs::remove(f.path(), ec); + if (!ec) ++removed; + } + } + } + } + } + + // Reset manifest state so initialize() knows it needs re-extraction + manifest_ = AssetManifest(); + initialized = false; + + LOG_INFO("Purge complete: ", removed, " entries removed from ", dataPath); + return removed; +} + std::string AssetManager::normalizePath(const std::string& path) const { std::string normalized = path; std::replace(normalized.begin(), normalized.end(), '/', '\\');