mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 01:53:52 +00:00
feat(extract): add --purge-proprietary mode to free disk after open conversion
Walks an extracted tree and removes every BLP/DBC/M2/skin/WMO/ADT
that has a confirmed open-format sidecar at least as new. Dry-run
by default — requires --confirm-purge to actually delete:
asset_extract --purge-proprietary Data/expansions/wotlk
Dry-run: would purge proprietary files...
would remove: 21570 files (16380.4 MB)
(re-run with --confirm-purge to actually delete)
asset_extract --purge-proprietary Data/expansions/wotlk --confirm-purge
Purging...
removed: 21570 files (16380.4 MB)
Pairing rules:
.blp → .png
.dbc → .json
.m2 → .wom
.skin → matching .m2's .wom (foo00.skin pairs with foo.wom)
.wmo → .wob (root)
.wmo group sub-files (foo_NNN.wmo) → parent foo.wob
.adt → .whm
Servers can't run without proprietary files, so this only makes
sense for wowee-runtime-only setups. Files without a sidecar are
left untouched.
This commit is contained in:
parent
5799b5f88f
commit
e547b4b82b
1 changed files with 98 additions and 0 deletions
|
|
@ -35,6 +35,10 @@ static void printUsage(const char* prog) {
|
|||
<< " --upgrade-extract <dir>\n"
|
||||
<< " Standalone post-extract pass on an existing tree —\n"
|
||||
<< " writes open-format sidecars without re-running MPQ extract\n"
|
||||
<< " --purge-proprietary <dir>\n"
|
||||
<< " Walk tree and dry-run report which proprietary files have\n"
|
||||
<< " an open-format sidecar; add --confirm-purge to actually delete\n"
|
||||
<< " --confirm-purge Required to actually delete files in --purge-proprietary mode\n"
|
||||
<< " --verify CRC32 verify all extracted files\n"
|
||||
<< " --threads <N> Number of extraction threads (default: auto)\n"
|
||||
<< " --verbose Verbose output\n"
|
||||
|
|
@ -51,6 +55,13 @@ int main(int argc, char** argv) {
|
|||
// it from MPQ. Triggered by --upgrade-extract <dir>.
|
||||
std::string upgradeDir;
|
||||
|
||||
// Purge proprietary files when their open-format sidecar is present
|
||||
// and at least as new. Dry-run by default; --confirm-purge actually
|
||||
// deletes. Lets users free disk after dual-format extraction when
|
||||
// they only need wowee runtime (no private server).
|
||||
std::string purgeDir;
|
||||
bool confirmPurge = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (std::strcmp(argv[i], "--mpq-dir") == 0 && i + 1 < argc) {
|
||||
opts.mpqDir = argv[++i];
|
||||
|
|
@ -95,6 +106,10 @@ int main(int argc, char** argv) {
|
|||
opts.verify = true;
|
||||
} else if (std::strcmp(argv[i], "--verbose") == 0) {
|
||||
opts.verbose = true;
|
||||
} else if (std::strcmp(argv[i], "--purge-proprietary") == 0 && i + 1 < argc) {
|
||||
purgeDir = argv[++i];
|
||||
} else if (std::strcmp(argv[i], "--confirm-purge") == 0) {
|
||||
confirmPurge = true;
|
||||
} else if (std::strcmp(argv[i], "--upgrade-extract") == 0 && i + 1 < argc) {
|
||||
upgradeDir = argv[++i];
|
||||
// Implies --emit-open if no individual emit flag was set.
|
||||
|
|
@ -113,6 +128,89 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// --purge-proprietary: walk a tree and (dry-run unless --confirm-purge)
|
||||
// remove every .blp/.dbc/.m2/.skin/.wmo/.adt that has a confirmed
|
||||
// open-format sidecar at least as new. Useful after a dual-format
|
||||
// extraction when the user only wants the open-format files (no
|
||||
// private-server compatibility needed).
|
||||
if (!purgeDir.empty()) {
|
||||
if (!std::filesystem::exists(purgeDir)) {
|
||||
std::cerr << "purge-proprietary: " << purgeDir << " does not exist\n";
|
||||
return 1;
|
||||
}
|
||||
std::cout << (confirmPurge ? "Purging" : "Dry-run: would purge")
|
||||
<< " proprietary files under " << purgeDir
|
||||
<< " where open-format sidecar exists...\n";
|
||||
// (proprietary ext, sidecar ext) pairs. .skin pairs with the
|
||||
// matching foo.m2's foo.wom (skin gets purged when WOM exists
|
||||
// because WOM stores merged geometry). Group .wmo (foo_NNN.wmo)
|
||||
// pair with the parent's .wob.
|
||||
struct Pair { const char* propExt; const char* sidecarExt; };
|
||||
const Pair pairs[] = {
|
||||
{".blp", ".png"},
|
||||
{".dbc", ".json"},
|
||||
{".m2", ".wom"},
|
||||
{".wmo", ".wob"}, // root WMO sidecar; group handling below
|
||||
{".adt", ".whm"},
|
||||
};
|
||||
uint64_t toRemove = 0, removed = 0, totalBytes = 0;
|
||||
namespace fs = std::filesystem;
|
||||
for (auto& entry : fs::recursive_directory_iterator(purgeDir)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
std::string p = entry.path().string();
|
||||
std::string ext = entry.path().extension().string();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
std::string base = p.substr(0, p.size() - ext.size());
|
||||
|
||||
// Skin file shares its WOM sidecar with the parent .m2.
|
||||
std::string sidecar;
|
||||
if (ext == ".skin") {
|
||||
// foo00.skin → foo.wom check
|
||||
if (base.size() >= 2 && base.substr(base.size() - 2) == "00") {
|
||||
sidecar = base.substr(0, base.size() - 2) + ".wom";
|
||||
}
|
||||
} else if (ext == ".wmo") {
|
||||
// Group sub-files purge if the parent root WMO has WOB.
|
||||
std::string fname = entry.path().filename().string();
|
||||
auto under = fname.rfind('_');
|
||||
bool isGroup = (under != std::string::npos &&
|
||||
fname.size() - under == 8);
|
||||
if (isGroup) {
|
||||
auto last = base.rfind('_');
|
||||
if (last != std::string::npos)
|
||||
sidecar = base.substr(0, last) + ".wob";
|
||||
} else {
|
||||
sidecar = base + ".wob";
|
||||
}
|
||||
} else {
|
||||
for (const auto& pr : pairs) {
|
||||
if (ext == pr.propExt) { sidecar = base + pr.sidecarExt; break; }
|
||||
}
|
||||
}
|
||||
if (sidecar.empty() || !fs::exists(sidecar)) continue;
|
||||
|
||||
std::error_code ec;
|
||||
auto srcMtime = fs::last_write_time(p, ec);
|
||||
auto sideMtime = fs::last_write_time(sidecar, ec);
|
||||
if (ec || sideMtime < srcMtime) continue;
|
||||
|
||||
toRemove++;
|
||||
totalBytes += entry.file_size();
|
||||
if (confirmPurge) {
|
||||
std::error_code rmEc;
|
||||
if (fs::remove(p, rmEc)) removed++;
|
||||
}
|
||||
}
|
||||
std::cout << (confirmPurge ? " removed: " : " would remove: ")
|
||||
<< toRemove << " files (" << (totalBytes / (1024.0 * 1024.0))
|
||||
<< " MB)\n";
|
||||
if (!confirmPurge) {
|
||||
std::cout << " (re-run with --confirm-purge to actually delete)\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --upgrade-extract: standalone post-extract pass on an existing tree.
|
||||
if (!upgradeDir.empty()) {
|
||||
if (!std::filesystem::exists(upgradeDir)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue