mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add per-expansion asset overlay system and fix CharSections DBC layout
Expansion overlays allow each expansion to supplement the base asset data via an assetManifest field in expansion.json, loaded at priority 50 (below HD packs). The asset extractor gains --reference-manifest for delta-only extraction. Also fixes CharSections field indices (VariationIndex=4, ColorIndex=5, Texture1=6) across all DBC layout references.
This commit is contained in:
parent
85864ab05b
commit
886f4daf2e
13 changed files with 151 additions and 46 deletions
|
|
@ -246,6 +246,58 @@ static std::unordered_set<std::string> buildWantedDbcSet(const Extractor::Option
|
|||
return wanted;
|
||||
}
|
||||
|
||||
// Load all entry keys from a manifest.json into a set of normalized WoW paths.
|
||||
// This is a minimal parser — just extracts the keys from the "entries" object
|
||||
// without pulling in a full JSON library.
|
||||
static std::unordered_set<std::string> loadManifestKeys(const std::string& manifestPath) {
|
||||
std::unordered_set<std::string> keys;
|
||||
std::ifstream f(manifestPath);
|
||||
if (!f.is_open()) {
|
||||
std::cerr << "Failed to open reference manifest: " << manifestPath << "\n";
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Find the "entries" section, then extract keys from each line
|
||||
bool inEntries = false;
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (!inEntries) {
|
||||
if (line.find("\"entries\"") != std::string::npos) {
|
||||
inEntries = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// End of entries block
|
||||
size_t closeBrace = line.find_first_not_of(" \t");
|
||||
if (closeBrace != std::string::npos && line[closeBrace] == '}') {
|
||||
break;
|
||||
}
|
||||
|
||||
// Extract key: find first quoted string on the line
|
||||
size_t q1 = line.find('"');
|
||||
if (q1 == std::string::npos) continue;
|
||||
size_t q2 = q1 + 1;
|
||||
// Find closing quote (handle escaped backslashes)
|
||||
std::string key;
|
||||
while (q2 < line.size() && line[q2] != '"') {
|
||||
if (line[q2] == '\\' && q2 + 1 < line.size()) {
|
||||
key += line[q2 + 1]; // unescape \\, \", etc.
|
||||
q2 += 2;
|
||||
} else {
|
||||
key += line[q2];
|
||||
q2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!key.empty()) {
|
||||
keys.insert(key); // Already normalized (lowercase, backslashes)
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Known WoW client locales
|
||||
static const std::vector<std::string> kKnownLocales = {
|
||||
"enUS", "enGB", "deDE", "frFR", "esES", "esMX",
|
||||
|
|
@ -485,6 +537,22 @@ bool Extractor::run(const Options& opts) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Delta extraction: filter out files that already exist in the reference manifest
|
||||
if (!opts.referenceManifest.empty()) {
|
||||
auto refKeys = loadManifestKeys(opts.referenceManifest);
|
||||
if (refKeys.empty()) {
|
||||
std::cerr << "Warning: reference manifest is empty or failed to load\n";
|
||||
} else {
|
||||
size_t before = files.size();
|
||||
files.erase(std::remove_if(files.begin(), files.end(),
|
||||
[&refKeys](const std::string& wowPath) {
|
||||
return refKeys.count(normalizeWowPath(wowPath)) > 0;
|
||||
}), files.end());
|
||||
std::cout << "Delta filter: " << before << " -> " << files.size()
|
||||
<< " files (" << (before - files.size()) << " already in reference)\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (files.empty()) {
|
||||
std::cerr << "No files to extract\n";
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
bool skipDbcExtraction = false; // Extract visual assets only (recommended when CSV DBCs are in repo)
|
||||
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/<exp>/db
|
||||
std::string referenceManifest; // If set, only extract files NOT in this manifest (delta extraction)
|
||||
};
|
||||
|
||||
struct Stats {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ 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"
|
||||
<< " <output>/expansions/<expansion>/db/*.csv (for committing)\n"
|
||||
<< " --reference-manifest <path>\n"
|
||||
<< " Only extract files NOT in this manifest (delta extraction)\n"
|
||||
<< " --dbc-csv-out <dir> Write CSV DBCs into <dir> (overrides default output path)\n"
|
||||
<< " --verify CRC32 verify all extracted files\n"
|
||||
<< " --threads <N> Number of extraction threads (default: auto)\n"
|
||||
|
|
@ -50,6 +52,8 @@ 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], "--reference-manifest") == 0 && i + 1 < argc) {
|
||||
opts.referenceManifest = argv[++i];
|
||||
} else if (std::strcmp(argv[i], "--verify") == 0) {
|
||||
opts.verify = true;
|
||||
} else if (std::strcmp(argv[i], "--verbose") == 0) {
|
||||
|
|
@ -114,6 +118,10 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!opts.referenceManifest.empty()) {
|
||||
std::cout << "Reference: " << opts.referenceManifest << " (delta mode)\n";
|
||||
}
|
||||
|
||||
if (!wowee::tools::Extractor::run(opts)) {
|
||||
std::cerr << "Extraction failed!\n";
|
||||
return 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue