diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f3653b1..0547f99c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ set(WOWEE_SOURCES src/pipeline/wmo_loader.cpp src/pipeline/adt_loader.cpp src/pipeline/dbc_layout.cpp - src/pipeline/hd_pack_manager.cpp + src/pipeline/terrain_mesh.cpp # Rendering diff --git a/include/core/application.hpp b/include/core/application.hpp index 1ad9ac48..a5af63bb 100644 --- a/include/core/application.hpp +++ b/include/core/application.hpp @@ -17,7 +17,7 @@ namespace rendering { class Renderer; } namespace ui { class UIManager; } namespace auth { class AuthHandler; } namespace game { class GameHandler; class World; class ExpansionRegistry; } -namespace pipeline { class AssetManager; class DBCLayout; class HDPackManager; } +namespace pipeline { class AssetManager; class DBCLayout; } namespace audio { enum class VoiceType; } namespace core { @@ -57,7 +57,6 @@ public: pipeline::AssetManager* getAssetManager() { return assetManager.get(); } game::ExpansionRegistry* getExpansionRegistry() { return expansionRegistry_.get(); } pipeline::DBCLayout* getDBCLayout() { return dbcLayout_.get(); } - pipeline::HDPackManager* getHDPackManager() { return hdPackManager_.get(); } void reloadExpansionData(); // Reload DBC layouts, opcodes, etc. after expansion change // Singleton access @@ -121,7 +120,6 @@ private: std::unique_ptr assetManager; std::unique_ptr expansionRegistry_; std::unique_ptr dbcLayout_; - std::unique_ptr hdPackManager_; AppState state = AppState::AUTHENTICATION; bool running = false; diff --git a/include/game/expansion_profile.hpp b/include/game/expansion_profile.hpp index 31e66974..7676b026 100644 --- a/include/game/expansion_profile.hpp +++ b/include/game/expansion_profile.hpp @@ -30,7 +30,6 @@ struct ExpansionProfile { std::string locale = "enUS"; uint32_t timezone = 0; std::string dataPath; // Absolute path to expansion data dir - std::string assetManifest; // Path to expansion-specific asset manifest (absolute, resolved from dataPath) uint32_t maxLevel = 60; std::vector races; std::vector classes; diff --git a/include/pipeline/asset_manager.hpp b/include/pipeline/asset_manager.hpp index bc087d2b..0dda631f 100644 --- a/include/pipeline/asset_manager.hpp +++ b/include/pipeline/asset_manager.hpp @@ -17,8 +17,8 @@ namespace pipeline { * AssetManager - Unified interface for loading WoW assets * * Reads pre-extracted loose files indexed by manifest.json. - * Supports layered manifests: overlay manifests (HD packs, mods) - * are checked before the base manifest, with higher priority first. + * Supports an override directory (Data/override/) checked before the manifest + * for HD textures, custom content, or mod overrides. * Use the asset_extract tool to extract MPQ archives first. * All reads are fully parallel (no serialization mutex needed). */ @@ -44,26 +44,6 @@ public: */ bool isInitialized() const { return initialized; } - /** - * Add an overlay manifest (HD packs, mods) checked before the base manifest. - * Higher priority overlays are checked first. - * @param manifestPath Full path to the overlay's manifest.json - * @param priority Priority level (higher = checked first) - * @param id Unique identifier for this overlay (e.g. "hd_character") - * @return true if overlay loaded successfully - */ - bool addOverlayManifest(const std::string& manifestPath, int priority, const std::string& id); - - /** - * Remove a previously added overlay manifest by id. - */ - void removeOverlay(const std::string& id); - - /** - * Get list of active overlay IDs. - */ - std::vector getOverlayIds() const; - /** * Load a BLP texture * @param path Virtual path to BLP file (e.g., "Textures\\Minimap\\Background.blp") @@ -140,24 +120,17 @@ private: bool initialized = false; std::string dataPath; std::string expansionDataPath_; // e.g. "Data/expansions/wotlk" + std::string overridePath_; // e.g. "Data/override" // Base manifest (loaded from dataPath/manifest.json) AssetManifest manifest_; LooseFileReader looseReader_; - // Overlay manifests (HD packs, mods) - sorted by priority descending - struct ManifestLayer { - AssetManifest manifest; - int priority; - std::string id; - }; - std::vector overlayLayers_; // Sorted by priority desc - /** - * Resolve filesystem path checking overlays first, then base manifest. - * Returns empty string if not found in any layer. + * Resolve filesystem path: check override dir first, then base manifest. + * Returns empty string if not found. */ - std::string resolveLayeredPath(const std::string& normalizedPath) const; + std::string resolveFile(const std::string& normalizedPath) const; mutable std::mutex cacheMutex; std::map> dbcCache; diff --git a/include/pipeline/hd_pack_manager.hpp b/include/pipeline/hd_pack_manager.hpp deleted file mode 100644 index 1eaa6ff2..00000000 --- a/include/pipeline/hd_pack_manager.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace wowee { -namespace pipeline { - -class AssetManager; - -/** - * Metadata for a single HD texture pack on disk. - * - * Each pack lives in Data/hd// and contains: - * pack.json - metadata (id, name, group, compatible expansions, size) - * manifest.json - standard asset manifest with HD override textures - * assets/ - the actual HD files - */ -struct HDPack { - std::string id; // Unique identifier (e.g. "character_hd") - std::string name; // Human-readable name - std::string group; // Grouping label (e.g. "Character", "Terrain") - std::vector expansions; // Compatible expansion IDs - uint32_t totalSizeMB = 0; // Approximate total size on disk - std::string manifestPath; // Full path to manifest.json - std::string packDir; // Full path to pack directory - bool enabled = false; // User-toggled enable state -}; - -/** - * HDPackManager - discovers, manages, and wires HD texture packs. - * - * Scans Data/hd/ subdirectories for pack.json files. Each pack can be - * enabled/disabled via setPackEnabled(). Enabled packs are wired into - * AssetManager as high-priority overlay manifests so that HD textures - * override the base expansion assets transparently. - */ -class HDPackManager { -public: - HDPackManager() = default; - - /** - * Scan the HD root directory for available packs. - * @param hdRootPath Path to Data/hd/ directory - */ - void initialize(const std::string& hdRootPath); - - /** - * Get all discovered packs. - */ - const std::vector& getAllPacks() const { return packs_; } - - /** - * Get packs compatible with a specific expansion. - */ - std::vector getPacksForExpansion(const std::string& expansionId) const; - - /** - * Enable or disable a pack. Persists state in enabledPacks_ map. - */ - void setPackEnabled(const std::string& packId, bool enabled); - - /** - * Check if a pack is enabled. - */ - bool isPackEnabled(const std::string& packId) const; - - /** - * Apply enabled packs as overlays to the asset manager. - * Removes previously applied overlays and re-adds enabled ones. - */ - void applyToAssetManager(AssetManager* assetManager, const std::string& expansionId); - - /** - * Save enabled pack state to a settings file. - */ - void saveSettings(const std::string& settingsPath) const; - - /** - * Load enabled pack state from a settings file. - */ - void loadSettings(const std::string& settingsPath); - -private: - std::vector packs_; - std::unordered_map enabledState_; // packId → enabled - - // Overlay IDs currently applied to AssetManager (for removal on re-apply) - std::vector appliedOverlayIds_; - - static constexpr int HD_OVERLAY_PRIORITY_BASE = 100; // High priority, above expansion base -}; - -} // namespace pipeline -} // namespace wowee diff --git a/src/core/application.cpp b/src/core/application.cpp index d9add317..c0ab2693 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -41,7 +41,7 @@ #include "game/packet_parsers.hpp" #include "pipeline/asset_manager.hpp" #include "pipeline/dbc_layout.hpp" -#include "pipeline/hd_pack_manager.hpp" + #include #include #include @@ -129,9 +129,6 @@ bool Application::initialize() { // Create DBC layout dbcLayout_ = std::make_unique(); - // Create HD pack manager - hdPackManager_ = std::make_unique(); - // Create asset manager assetManager = std::make_unique(); @@ -211,37 +208,6 @@ bool Application::initialize() { gameHandler->getTransportManager()->loadTaxiPathNodeDBC(assetManager.get()); } - // Initialize HD texture packs - if (hdPackManager_) { - std::string hdPath = dataPath + "/hd"; - std::string settingsDir; - const char* xdg = std::getenv("XDG_DATA_HOME"); - if (xdg && *xdg) { - settingsDir = std::string(xdg) + "/wowee"; - } else { - const char* home = std::getenv("HOME"); - settingsDir = std::string(home ? home : ".") + "/.local/share/wowee"; - } - hdPackManager_->loadSettings(settingsDir + "/settings.cfg"); - hdPackManager_->initialize(hdPath); - - // Apply enabled packs as overlays - std::string expansionId = "wotlk"; - if (expansionRegistry_ && expansionRegistry_->getActive()) { - expansionId = expansionRegistry_->getActive()->id; - } - hdPackManager_->applyToAssetManager(assetManager.get(), expansionId); - } - - // Load expansion-specific asset overlay (priority 50, below HD packs at 100+) - if (expansionRegistry_) { - auto* activeProfile = expansionRegistry_->getActive(); - if (activeProfile && !activeProfile->assetManifest.empty()) { - if (assetManager->addOverlayManifest(activeProfile->assetManifest, 50, "expansion_overlay")) { - LOG_INFO("Added expansion asset overlay: ", activeProfile->assetManifest); - } - } - } } else { LOG_WARNING("Failed to initialize asset manager - asset loading will be unavailable"); LOG_WARNING("Set WOW_DATA_PATH environment variable to your WoW Data directory"); @@ -504,14 +470,6 @@ void Application::reloadExpansionData() { if (assetManager && !profile->dataPath.empty()) { assetManager->setExpansionDataPath(profile->dataPath); assetManager->clearDBCCache(); - - // Swap expansion asset overlay - assetManager->removeOverlay("expansion_overlay"); - if (!profile->assetManifest.empty()) { - if (assetManager->addOverlayManifest(profile->assetManifest, 50, "expansion_overlay")) { - LOG_INFO("Swapped expansion asset overlay: ", profile->assetManifest); - } - } } // Reset map name cache so it reloads from new expansion's Map.dbc diff --git a/src/game/expansion_profile.cpp b/src/game/expansion_profile.cpp index 00aa068d..9b14e0b7 100644 --- a/src/game/expansion_profile.cpp +++ b/src/game/expansion_profile.cpp @@ -176,12 +176,6 @@ bool ExpansionRegistry::loadProfile(const std::string& jsonPath, const std::stri v = jsonValue(json, "locale"); if (!v.empty()) p.locale = v; p.timezone = static_cast(jsonInt(json, "timezone", static_cast(p.timezone))); } - // Expansion-specific asset manifest (overlay for base data) - p.assetManifest = jsonValue(json, "assetManifest"); - if (!p.assetManifest.empty() && p.assetManifest[0] != '/') { - p.assetManifest = dirPath + "/" + p.assetManifest; - } - p.maxLevel = static_cast(jsonInt(json, "maxLevel", 60)); p.races = jsonUintArray(json, "races"); p.classes = jsonUintArray(json, "classes"); diff --git a/src/pipeline/asset_manager.cpp b/src/pipeline/asset_manager.cpp index 27a43311..2c6e409a 100644 --- a/src/pipeline/asset_manager.cpp +++ b/src/pipeline/asset_manager.cpp @@ -42,6 +42,7 @@ bool AssetManager::initialize(const std::string& dataPath_) { } dataPath = dataPath_; + overridePath_ = dataPath + "/override"; LOG_INFO("Initializing asset manager with data path: ", dataPath); setupFileCacheBudget(); @@ -58,6 +59,10 @@ bool AssetManager::initialize(const std::string& dataPath_) { return false; } + if (std::filesystem::is_directory(overridePath_)) { + LOG_INFO("Override directory found: ", overridePath_); + } + initialized = true; LOG_INFO("Asset manager initialized: ", manifest_.getEntryCount(), " files indexed (file cache: ", fileCacheBudget / (1024 * 1024), " MB)"); @@ -104,97 +109,18 @@ void AssetManager::shutdown() { } clearCache(); - overlayLayers_.clear(); initialized = false; } -bool AssetManager::addOverlayManifest(const std::string& manifestPath, int priority, const std::string& id) { - // Check for duplicate - for (const auto& layer : overlayLayers_) { - if (layer.id == id) { - LOG_WARNING("Overlay '", id, "' already loaded, skipping"); - return false; - } - } - - ManifestLayer layer; - layer.priority = priority; - layer.id = id; - - if (!layer.manifest.load(manifestPath)) { - LOG_ERROR("Failed to load overlay manifest: ", manifestPath); - return false; - } - - overlayLayers_.push_back(std::move(layer)); - - // Sort by priority descending (highest priority first) - std::sort(overlayLayers_.begin(), overlayLayers_.end(), - [](const ManifestLayer& a, const ManifestLayer& b) { - return a.priority > b.priority; - }); - - LOG_INFO("Added overlay '", id, "' (priority ", priority, ", ", - overlayLayers_.back().manifest.getEntryCount(), " files) from ", manifestPath); - return true; -} - -void AssetManager::removeOverlay(const std::string& id) { - auto it = std::remove_if(overlayLayers_.begin(), overlayLayers_.end(), - [&id](const ManifestLayer& layer) { return layer.id == id; }); - if (it != overlayLayers_.end()) { - overlayLayers_.erase(it, overlayLayers_.end()); - // Clear file cache since overlay removal changes file resolution - { - std::lock_guard lock(cacheMutex); - fileCache.clear(); - fileCacheTotalBytes = 0; - } - LOG_INFO("Removed overlay '", id, "', file cache cleared"); - } -} - -std::vector AssetManager::getOverlayIds() const { - std::vector ids; - ids.reserve(overlayLayers_.size()); - for (const auto& layer : overlayLayers_) { - ids.push_back(layer.id); - } - return ids; -} - -std::string AssetManager::resolveLayeredPath(const std::string& normalizedPath) const { - // For textures (.blp), pick the highest-resolution variant across overlays/base. - // Turtle/classic overlays can include lower-res textures; the base dataset may have higher-res. - auto isBlpTexture = [&]() -> bool { - return normalizedPath.size() >= 4 && - normalizedPath.compare(normalizedPath.size() - 4, 4, ".blp") == 0; - }; - - if (isBlpTexture()) { - uint64_t bestSize = 0; - std::string bestFsPath; - - auto consider = [&](const AssetManifest& m) { - if (const auto* e = m.lookup(normalizedPath)) { - if (e->size > bestSize) { - bestSize = e->size; - bestFsPath = m.getBasePath() + "/" + e->filesystemPath; - } +std::string AssetManager::resolveFile(const std::string& normalizedPath) const { + // Check override directory first (for HD upgrades, custom textures) + if (!overridePath_.empty()) { + const auto* entry = manifest_.lookup(normalizedPath); + if (entry && !entry->filesystemPath.empty()) { + std::string overrideFsPath = overridePath_ + "/" + entry->filesystemPath; + if (LooseFileReader::fileExists(overrideFsPath)) { + return overrideFsPath; } - }; - - for (const auto& layer : overlayLayers_) consider(layer.manifest); - consider(manifest_); - - if (!bestFsPath.empty()) return bestFsPath; - } - - // Default: check overlay manifests first (sorted by priority desc) - for (const auto& layer : overlayLayers_) { - std::string fsPath = layer.manifest.resolveFilesystemPath(normalizedPath); - if (!fsPath.empty()) { - return fsPath; } } // Fall back to base manifest @@ -239,7 +165,7 @@ BLPImage AssetManager::tryLoadPngOverride(const std::string& normalizedPath) con std::string ext = normalizedPath.substr(normalizedPath.size() - 4); if (ext != ".blp") return BLPImage(); - std::string fsPath = resolveLayeredPath(normalizedPath); + std::string fsPath = resolveFile(normalizedPath); if (fsPath.empty()) return BLPImage(); // Replace .blp/.BLP extension with .png @@ -398,12 +324,6 @@ bool AssetManager::fileExists(const std::string& path) const { return false; } std::string normalized = normalizePath(path); - // Check overlay manifests first - for (const auto& layer : overlayLayers_) { - if (layer.manifest.hasEntry(normalized)) { - return true; - } - } return manifest_.hasEntry(normalized); } @@ -425,8 +345,8 @@ std::vector AssetManager::readFile(const std::string& path) const { } } - // Read from filesystem using layered resolution (overlays first, then base) - std::string fsPath = resolveLayeredPath(normalized); + // Read from filesystem (override dir first, then base manifest) + std::string fsPath = resolveFile(normalized); if (fsPath.empty()) { return {}; } diff --git a/src/pipeline/hd_pack_manager.cpp b/src/pipeline/hd_pack_manager.cpp deleted file mode 100644 index 0e068f87..00000000 --- a/src/pipeline/hd_pack_manager.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "pipeline/hd_pack_manager.hpp" -#include "pipeline/asset_manager.hpp" -#include "core/logger.hpp" -#include -#include -#include -#include - -namespace wowee { -namespace pipeline { - -namespace { -// Minimal JSON string value parser (key must be unique in the flat object) -std::string jsonStringValue(const std::string& json, const std::string& key) { - std::string needle = "\"" + key + "\""; - size_t pos = json.find(needle); - if (pos == std::string::npos) return ""; - pos = json.find(':', pos + needle.size()); - if (pos == std::string::npos) return ""; - pos = json.find('"', pos + 1); - if (pos == std::string::npos) return ""; - size_t end = json.find('"', pos + 1); - if (end == std::string::npos) return ""; - return json.substr(pos + 1, end - pos - 1); -} - -// Parse a JSON number value -uint32_t jsonUintValue(const std::string& json, const std::string& key) { - std::string needle = "\"" + key + "\""; - size_t pos = json.find(needle); - if (pos == std::string::npos) return 0; - pos = json.find(':', pos + needle.size()); - if (pos == std::string::npos) return 0; - ++pos; - while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t')) ++pos; - return static_cast(std::strtoul(json.c_str() + pos, nullptr, 10)); -} - -// Parse a JSON string array value -std::vector jsonStringArray(const std::string& json, const std::string& key) { - std::vector result; - std::string needle = "\"" + key + "\""; - size_t pos = json.find(needle); - if (pos == std::string::npos) return result; - pos = json.find('[', pos + needle.size()); - if (pos == std::string::npos) return result; - size_t end = json.find(']', pos); - if (end == std::string::npos) return result; - std::string arr = json.substr(pos + 1, end - pos - 1); - size_t p = 0; - while (p < arr.size()) { - size_t qs = arr.find('"', p); - if (qs == std::string::npos) break; - size_t qe = arr.find('"', qs + 1); - if (qe == std::string::npos) break; - result.push_back(arr.substr(qs + 1, qe - qs - 1)); - p = qe + 1; - } - return result; -} -} // namespace - -void HDPackManager::initialize(const std::string& hdRootPath) { - packs_.clear(); - - if (!std::filesystem::exists(hdRootPath) || !std::filesystem::is_directory(hdRootPath)) { - LOG_DEBUG("HD pack directory not found: ", hdRootPath); - return; - } - - for (const auto& entry : std::filesystem::directory_iterator(hdRootPath)) { - if (!entry.is_directory()) continue; - - std::string packJsonPath = entry.path().string() + "/pack.json"; - if (!std::filesystem::exists(packJsonPath)) continue; - - std::ifstream f(packJsonPath); - if (!f.is_open()) continue; - - std::string json((std::istreambuf_iterator(f)), std::istreambuf_iterator()); - - HDPack pack; - pack.id = jsonStringValue(json, "id"); - pack.name = jsonStringValue(json, "name"); - pack.group = jsonStringValue(json, "group"); - pack.totalSizeMB = jsonUintValue(json, "totalSizeMB"); - pack.expansions = jsonStringArray(json, "expansions"); - pack.packDir = entry.path().string(); - pack.manifestPath = entry.path().string() + "/manifest.json"; - - if (pack.id.empty()) { - LOG_WARNING("HD pack in ", entry.path().string(), " has no id, skipping"); - continue; - } - - if (!std::filesystem::exists(pack.manifestPath)) { - LOG_WARNING("HD pack '", pack.id, "' missing manifest.json, skipping"); - continue; - } - - // Apply saved enabled state if available - auto it = enabledState_.find(pack.id); - if (it != enabledState_.end()) { - pack.enabled = it->second; - } - - LOG_INFO("Discovered HD pack: '", pack.id, "' (", pack.name, ") ", - pack.totalSizeMB, " MB, ", pack.expansions.size(), " expansions"); - packs_.push_back(std::move(pack)); - } - - LOG_INFO("HDPackManager: found ", packs_.size(), " packs in ", hdRootPath); -} - -std::vector HDPackManager::getPacksForExpansion(const std::string& expansionId) const { - std::vector result; - for (const auto& pack : packs_) { - if (pack.expansions.empty()) { - // No expansion filter = compatible with all - result.push_back(&pack); - } else { - for (const auto& exp : pack.expansions) { - if (exp == expansionId) { - result.push_back(&pack); - break; - } - } - } - } - return result; -} - -void HDPackManager::setPackEnabled(const std::string& packId, bool enabled) { - enabledState_[packId] = enabled; - for (auto& pack : packs_) { - if (pack.id == packId) { - pack.enabled = enabled; - break; - } - } -} - -bool HDPackManager::isPackEnabled(const std::string& packId) const { - auto it = enabledState_.find(packId); - return it != enabledState_.end() && it->second; -} - -void HDPackManager::applyToAssetManager(AssetManager* assetManager, const std::string& expansionId) { - if (!assetManager) return; - - // Remove previously applied overlays - for (const auto& overlayId : appliedOverlayIds_) { - assetManager->removeOverlay(overlayId); - } - appliedOverlayIds_.clear(); - - // Get packs compatible with current expansion - auto compatiblePacks = getPacksForExpansion(expansionId); - int priorityOffset = 0; - - for (const auto* pack : compatiblePacks) { - if (!pack->enabled) continue; - - std::string overlayId = "hd_" + pack->id; - int priority = HD_OVERLAY_PRIORITY_BASE + priorityOffset; - - if (assetManager->addOverlayManifest(pack->manifestPath, priority, overlayId)) { - appliedOverlayIds_.push_back(overlayId); - LOG_INFO("Applied HD pack '", pack->id, "' as overlay (priority ", priority, ")"); - } - ++priorityOffset; - } - - if (!appliedOverlayIds_.empty()) { - LOG_INFO("Applied ", appliedOverlayIds_.size(), " HD pack overlays"); - } -} - -void HDPackManager::saveSettings(const std::string& settingsPath) const { - std::ofstream f(settingsPath, std::ios::app); - if (!f.is_open()) return; - - for (const auto& [packId, enabled] : enabledState_) { - f << "hd_pack_" << packId << "=" << (enabled ? "1" : "0") << "\n"; - } -} - -void HDPackManager::loadSettings(const std::string& settingsPath) { - std::ifstream f(settingsPath); - if (!f.is_open()) return; - - std::string line; - while (std::getline(f, line)) { - if (line.substr(0, 8) != "hd_pack_") continue; - size_t eq = line.find('='); - if (eq == std::string::npos) continue; - std::string packId = line.substr(8, eq - 8); - bool enabled = (line.substr(eq + 1) == "1"); - enabledState_[packId] = enabled; - } -} - -} // namespace pipeline -} // namespace wowee diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 872c8886..d65d5862 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -23,7 +23,7 @@ #include "pipeline/dbc_loader.hpp" #include "pipeline/blp_loader.hpp" #include "pipeline/dbc_layout.hpp" -#include "pipeline/hd_pack_manager.hpp" + #include "game/expansion_profile.hpp" #include "core/logger.hpp" #include @@ -5449,79 +5449,6 @@ void GameScreen::renderSettingsWindow() { ImGui::EndTabItem(); } - // ============================================================ - // HD TEXTURES TAB - // ============================================================ - if (ImGui::BeginTabItem("HD Textures")) { - ImGui::Spacing(); - - auto& app = core::Application::getInstance(); - auto* hdMgr = app.getHDPackManager(); - - if (hdMgr) { - const auto& packs = hdMgr->getAllPacks(); - if (packs.empty()) { - ImGui::TextWrapped("No HD texture packs found."); - ImGui::Spacing(); - ImGui::TextWrapped("Place packs in Data/hd// with a pack.json and manifest.json."); - } else { - ImGui::Text("Available HD Texture Packs:"); - ImGui::Spacing(); - - bool changed = false; - for (const auto& pack : packs) { - bool enabled = pack.enabled; - if (ImGui::Checkbox(pack.name.c_str(), &enabled)) { - hdMgr->setPackEnabled(pack.id, enabled); - changed = true; - } - ImGui::SameLine(0, 10); - ImGui::TextDisabled("(%u MB)", pack.totalSizeMB); - if (!pack.group.empty()) { - ImGui::SameLine(0, 10); - ImGui::TextDisabled("[%s]", pack.group.c_str()); - } - if (!pack.expansions.empty()) { - std::string expList; - for (const auto& e : pack.expansions) { - if (!expList.empty()) expList += ", "; - expList += e; - } - ImGui::TextDisabled(" Compatible: %s", expList.c_str()); - } - } - - if (changed) { - ImGui::Spacing(); - ImGui::Separator(); - ImGui::Spacing(); - if (ImGui::Button("Apply HD Packs", ImVec2(-1, 0))) { - std::string expansionId = "wotlk"; - if (app.getExpansionRegistry() && app.getExpansionRegistry()->getActive()) { - expansionId = app.getExpansionRegistry()->getActive()->id; - } - hdMgr->applyToAssetManager(app.getAssetManager(), expansionId); - - // Save settings - std::string settingsDir; - const char* xdg = std::getenv("XDG_DATA_HOME"); - if (xdg && *xdg) { - settingsDir = std::string(xdg) + "/wowee"; - } else { - const char* home = std::getenv("HOME"); - settingsDir = std::string(home ? home : ".") + "/.local/share/wowee"; - } - hdMgr->saveSettings(settingsDir + "/settings.cfg"); - } - } - } - } else { - ImGui::Text("HD Pack Manager not available."); - } - - ImGui::EndTabItem(); - } - // ============================================================ // CHAT TAB // ============================================================ diff --git a/tools/asset_extract/extractor.cpp b/tools/asset_extract/extractor.cpp index 8454c7f2..b4b6c9d5 100644 --- a/tools/asset_extract/extractor.cpp +++ b/tools/asset_extract/extractor.cpp @@ -570,28 +570,7 @@ bool Extractor::enumerateFiles(const Options& opts, bool Extractor::run(const Options& opts) { auto startTime = std::chrono::steady_clock::now(); - const bool overlayMode = !opts.asOverlay.empty(); - - // Overlay mode writes files to expansions//overlay/ under the output dir - const std::string effectiveOutputDir = overlayMode - ? opts.outputDir + "/expansions/" + opts.asOverlay + "/overlay" - : opts.outputDir; - - // Load base manifest CRCs for overlay deduplication - std::unordered_map baseCRCs; - if (overlayMode) { - std::string baseManifestPath = opts.outputDir + "/manifest.json"; - auto baseEntries = loadManifestEntries(baseManifestPath); - if (baseEntries.empty()) { - std::cerr << "Warning: base manifest empty or missing at " << baseManifestPath << "\n" - << " Extract the base expansion first, then use --as-overlay for others.\n"; - } else { - for (auto& [k, v] : baseEntries) { - baseCRCs[k] = v.crc32; - } - std::cout << "Loaded " << baseCRCs.size() << " base manifest entries for CRC comparison\n"; - } - } + const std::string effectiveOutputDir = opts.outputDir; // Enumerate all unique files across all archives std::vector files; @@ -708,15 +687,6 @@ bool Extractor::run(const Options& opts) { // Compute CRC32 uint32_t crc = ManifestWriter::computeCRC32(data.data(), data.size()); - // In overlay mode, skip files identical to base - if (!baseCRCs.empty()) { - auto it = baseCRCs.find(normalized); - if (it != baseCRCs.end() && it->second == crc) { - stats.filesSkipped++; - continue; - } - } - // Create output directory and write file fs::path outPath(fullOutputPath); fs::create_directories(outPath.parent_path(), ec); @@ -773,9 +743,8 @@ bool Extractor::run(const Options& opts) { << stats.filesFailed.load() << " failed\n"; // Merge with existing manifest so partial extractions don't nuke prior entries - // (skip merge for overlay manifests — they're standalone) std::string manifestPath = effectiveOutputDir + "/manifest.json"; - if (!overlayMode && fs::exists(manifestPath)) { + if (fs::exists(manifestPath)) { auto existing = loadManifestEntries(manifestPath); if (!existing.empty()) { // New entries override existing ones with same key @@ -853,7 +822,7 @@ bool Extractor::run(const Options& opts) { if (opts.generateDbcCsv) { std::cout << "Converting selected DBCs to CSV for committing...\n"; const std::string dbcDir = effectiveOutputDir + "/db"; - const std::string csvExpansion = overlayMode ? opts.asOverlay : opts.expansion; + const std::string csvExpansion = opts.expansion; const std::string csvDir = !opts.dbcCsvOutputDir.empty() ? opts.dbcCsvOutputDir : (opts.outputDir + "/expansions/" + csvExpansion + "/db"); @@ -885,8 +854,8 @@ bool Extractor::run(const Options& opts) { } } - // Cache WoW.exe for Warden MEM_CHECK responses (base extraction only) - if (!overlayMode) { + // Cache WoW.exe for Warden MEM_CHECK responses + { const char* exeNames[] = { "WoW.exe", "TurtleWoW.exe", "Wow.exe" }; std::vector searchDirs = { fs::path(opts.mpqDir).parent_path().string(), // WoW.exe is typically next to Data/ @@ -910,41 +879,6 @@ bool Extractor::run(const Options& opts) { } } - // Auto-update expansion.json with assetManifest field - if (overlayMode) { - std::string expJsonPath = opts.outputDir + "/expansions/" + opts.asOverlay + "/expansion.json"; - if (fs::exists(expJsonPath)) { - std::ifstream fin(expJsonPath); - std::string content((std::istreambuf_iterator(fin)), - std::istreambuf_iterator()); - fin.close(); - - if (content.find("\"assetManifest\"") == std::string::npos) { - // Insert assetManifest before the closing brace - size_t lastBrace = content.rfind('}'); - if (lastBrace != std::string::npos) { - // Find the last non-whitespace before the closing brace to add comma - size_t pos = lastBrace; - while (pos > 0 && (content[pos - 1] == ' ' || content[pos - 1] == '\n' || - content[pos - 1] == '\r' || content[pos - 1] == '\t')) { - pos--; - } - std::string insert = ",\n \"assetManifest\": \"overlay/manifest.json\"\n"; - content.insert(pos, insert); - - std::ofstream fout(expJsonPath); - fout << content; - fout.close(); - std::cout << "Updated " << expJsonPath << " with assetManifest\n"; - } - } else { - std::cout << "expansion.json already has assetManifest field\n"; - } - } else { - std::cerr << "Warning: " << expJsonPath << " not found — create it manually\n"; - } - } - std::cout << "Done in " << secs / 60 << "m " << secs % 60 << "s\n"; return true; diff --git a/tools/asset_extract/extractor.hpp b/tools/asset_extract/extractor.hpp index ff7e894c..e9aa646d 100644 --- a/tools/asset_extract/extractor.hpp +++ b/tools/asset_extract/extractor.hpp @@ -26,7 +26,6 @@ public: bool onlyUsedDbcs = false; // Extract only the DBC files wowee uses (implies DBFilesClient/*.dbc filter) std::string dbcCsvOutputDir; // When set, write CSVs into this directory instead of outputDir/expansions//db std::string referenceManifest; // If set, only extract files NOT in this manifest (delta extraction) - std::string asOverlay; // If set, extract as overlay for this expansion ID (only files differing from base) }; struct Stats { diff --git a/tools/asset_extract/main.cpp b/tools/asset_extract/main.cpp index 5480259c..6d9c27f5 100644 --- a/tools/asset_extract/main.cpp +++ b/tools/asset_extract/main.cpp @@ -20,11 +20,6 @@ static void printUsage(const char* prog) { << " --skip-dbc Do not extract DBFilesClient/*.dbc (visual assets only)\n" << " --dbc-csv Convert selected DBFilesClient/*.dbc to CSV under\n" << " /expansions//db/*.csv (for committing)\n" - << " --as-overlay Extract as expansion overlay (only files differing from base\n" - << " manifest at /manifest.json). Stores overlay assets in\n" - << " /expansions//overlay/ and implies --dbc-csv.\n" - << " Auto-detected when base manifest already exists.\n" - << " --full-base Force full base extraction even if manifest exists\n" << " --reference-manifest \n" << " Only extract files NOT in this manifest (delta extraction)\n" << " --dbc-csv-out Write CSV DBCs into (overrides default output path)\n" @@ -38,7 +33,6 @@ int main(int argc, char** argv) { wowee::tools::Extractor::Options opts; std::string expansion; std::string locale; - bool forceBase = false; for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--mpq-dir") == 0 && i + 1 < argc) { @@ -59,11 +53,6 @@ int main(int argc, char** argv) { opts.generateDbcCsv = true; } else if (std::strcmp(argv[i], "--dbc-csv-out") == 0 && i + 1 < argc) { opts.dbcCsvOutputDir = argv[++i]; - } else if (std::strcmp(argv[i], "--as-overlay") == 0 && i + 1 < argc) { - opts.asOverlay = argv[++i]; - opts.generateDbcCsv = true; // Overlay mode always generates per-expansion CSVs - } else if (std::strcmp(argv[i], "--full-base") == 0) { - forceBase = true; } else if (std::strcmp(argv[i], "--reference-manifest") == 0 && i + 1 < argc) { opts.referenceManifest = argv[++i]; } else if (std::strcmp(argv[i], "--verify") == 0) { @@ -110,20 +99,6 @@ int main(int argc, char** argv) { } opts.locale = locale; - // Auto-detect overlay mode: if a base manifest already exists and this expansion - // has a profile directory, automatically use overlay mode so the user doesn't have - // to think about extraction order. - if (opts.asOverlay.empty() && !forceBase && !opts.onlyUsedDbcs) { - namespace fs = std::filesystem; - std::string baseManifest = opts.outputDir + "/manifest.json"; - std::string expJson = opts.outputDir + "/expansions/" + expansion + "/expansion.json"; - if (fs::exists(baseManifest) && fs::exists(expJson)) { - opts.asOverlay = expansion; - opts.generateDbcCsv = true; - std::cout << "Base manifest found — auto-overlay mode for " << expansion << "\n"; - } - } - std::cout << "=== Wowee Asset Extractor ===\n"; std::cout << "MPQ directory: " << opts.mpqDir << "\n"; std::cout << "Output: " << opts.outputDir << "\n"; @@ -144,9 +119,6 @@ int main(int argc, char** argv) { } } - if (!opts.asOverlay.empty()) { - std::cout << "Overlay: " << opts.asOverlay << " (only files differing from base)\n"; - } if (!opts.referenceManifest.empty()) { std::cout << "Reference: " << opts.referenceManifest << " (delta mode)\n"; }