feat(editor): add --migrate-zone for batch WOM upgrade across a zone

Companion to --migrate-wom (single-file upgrade). Walks a zone dir
recursively and upgrades every legacy WOM (v1/v2 with no batches[])
to WOM3 in-place:

  wowee_editor --migrate-zone custom_zones/MyZone

  upgraded: custom_zones/MyZone/models/v1_0.wom
  upgraded: custom_zones/MyZone/models/v1_1.wom

  migrate-zone: custom_zones/MyZone
    scanned   : 3 WOM file(s)
    upgraded  : 2 (added single-batch entry)
    already v3: 1 (no change needed)

Idempotent: already-migrated files become no-ops, so it's safe to
run inside --for-each-zone over a whole project. Useful when the
editor adds a new WOM3-only feature and legacy zones need a one-shot
upgrade pass.

Returns exit 1 if any file fails to write (separate from 'no upgrade
needed'), so CI can gate on it.

Verified: seeded a dir with 2 v1 WOMs + 1 v3 WOM. First run
upgraded 2, reported 1 as already-v3. Re-run reported all 3 as
already-v3 (no double-batching).
This commit is contained in:
Kelsi 2026-05-06 13:44:16 -07:00
parent b3e34e0edf
commit 6d79963f24

View file

@ -416,6 +416,8 @@ static void printUsage(const char* argv0) {
std::printf(" Convert one BLP texture to PNG sidecar\n");
std::printf(" --migrate-wom <wom-base> [out-base]\n");
std::printf(" Upgrade an older WOM (v1/v2) to WOM3 with a default single-batch entry\n");
std::printf(" --migrate-zone <zoneDir>\n");
std::printf(" Run --migrate-wom in-place on every WOM under <zoneDir>\n");
std::printf(" --list-zones [--json] List discovered custom zones and exit\n");
std::printf(" --zone-stats <projectDir> [--json]\n");
std::printf(" Aggregate counts across every zone in <projectDir>\n");
@ -623,7 +625,7 @@ int main(int argc, char* argv[]) {
"--export-glb", "--export-wob-glb", "--export-whm-glb",
"--convert-m2", "--convert-wmo",
"--convert-dbc-json", "--convert-json-dbc", "--convert-blp-png",
"--migrate-wom",
"--migrate-wom", "--migrate-zone",
};
for (int i = 1; i < argc; i++) {
for (const char* opt : kArgRequired) {
@ -7460,6 +7462,55 @@ int main(int argc, char* argv[]) {
}
return 0;
}
if (std::strcmp(argv[i], "--migrate-zone") == 0 && i + 1 < argc) {
// Batch-runs --migrate-wom in-place on every .wom under
// a zone directory. Idempotent (already-migrated files
// become no-ops). Useful when wowee_editor adds a new
// WOM3-only feature and you want to upgrade legacy zones
// in one shot.
std::string zoneDir = argv[++i];
namespace fs = std::filesystem;
if (!fs::exists(zoneDir) || !fs::is_directory(zoneDir)) {
std::fprintf(stderr,
"migrate-zone: %s is not a directory\n", zoneDir.c_str());
return 1;
}
int scanned = 0, upgraded = 0, alreadyV3 = 0, failed = 0;
std::error_code ec;
for (const auto& e : fs::recursive_directory_iterator(zoneDir, ec)) {
if (!e.is_regular_file()) continue;
std::string ext = e.path().extension().string();
if (ext != ".wom") continue;
scanned++;
std::string base = e.path().string();
if (base.size() >= 4) base = base.substr(0, base.size() - 4);
auto wom = wowee::pipeline::WoweeModelLoader::load(base);
if (!wom.isValid()) { failed++; continue; }
if (!wom.batches.empty()) { alreadyV3++; continue; }
wowee::pipeline::WoweeModel::Batch b;
b.indexStart = 0;
b.indexCount = static_cast<uint32_t>(wom.indices.size());
b.textureIndex = 0;
b.blendMode = 0;
b.flags = 0;
wom.batches.push_back(b);
if (wowee::pipeline::WoweeModelLoader::save(wom, base)) {
upgraded++;
std::printf(" upgraded: %s.wom\n", base.c_str());
} else {
failed++;
std::fprintf(stderr, " FAILED: %s.wom\n", base.c_str());
}
}
std::printf("\nmigrate-zone: %s\n", zoneDir.c_str());
std::printf(" scanned : %d WOM file(s)\n", scanned);
std::printf(" upgraded : %d (added single-batch entry)\n", upgraded);
std::printf(" already v3: %d (no change needed)\n", alreadyV3);
if (failed > 0) {
std::printf(" FAILED : %d (see stderr)\n", failed);
}
return failed == 0 ? 0 : 1;
}
}
if (dataPath.empty()) {