From 5efd5b157da506aab1736e85af9f9c11996728d2 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 22:55:39 -0700 Subject: [PATCH] =?UTF-8?q?feat(editor):=20add=20--convert-m2-batch=20for?= =?UTF-8?q?=20bulk=20M2=E2=86=92WOM=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Walks recursively for every .m2 file (case-insensitive, including subdirs) and re-invokes --convert-m2 per file via a child process so the existing single-file logic — AssetManager init, skin file resolution, fromM2() pipeline — is reused verbatim. Per-file [ok]/[FAIL] line streamed live; aggregate summary at the end. Designed to migrate an entire creature/world model dump in one go. This is the headline open-format conversion: every .m2 in a proprietary data tree gets turned into a .wom open-format model. Pair with the upcoming --convert-wmo-batch / --convert-blp-batch / --convert-dbc-batch to migrate a complete extracted Data tree. Verified discovery: 3 placeholder .m2 files (one in subdir, one .M2 uppercase) found correctly; .txt skipped; all fail conversion as expected for empty bytes; exit 1 on any failure. Brings command count to 183. --- tools/editor/main.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index e9c7ab4a..bd663fbe 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -503,6 +503,8 @@ static void printUsage(const char* argv0) { std::printf(" --data Path to extracted WoW data (manifest.json)\n"); std::printf(" --adt Load an ADT tile on startup\n"); std::printf(" --convert-m2 Convert M2 model to WOM open format (no GUI)\n"); + std::printf(" --convert-m2-batch \n"); + std::printf(" Bulk M2→WOM conversion across every .m2 in (per-file pass/fail summary)\n"); std::printf(" --convert-wmo Convert WMO building to WOB open format (no GUI)\n"); std::printf(" --convert-dbc-json [out.json]\n"); std::printf(" Convert one DBC file to wowee JSON sidecar format\n"); @@ -919,7 +921,8 @@ int main(int argc, char* argv[]) { "--export-stl", "--import-stl", "--bake-zone-glb", "--bake-zone-stl", "--bake-zone-obj", "--bake-project-obj", "--bake-project-stl", "--bake-project-glb", - "--convert-m2", "--convert-wmo", + "--convert-m2", "--convert-m2-batch", + "--convert-wmo", "--convert-dbc-json", "--convert-json-dbc", "--convert-blp-png", "--migrate-wom", "--migrate-zone", "--migrate-project", "--migrate-jsondbc", @@ -13287,6 +13290,56 @@ int main(int argc, char* argv[]) { std::printf(" pass --dry-run off to actually delete\n"); } return totalFailed == 0 ? 0 : 1; + } else if (std::strcmp(argv[i], "--convert-m2-batch") == 0 && i + 1 < argc) { + // Bulk M2→WOM conversion. Walks recursively for + // every .m2 file and re-invokes --convert-m2 per file via + // a child process so the existing single-file logic (with + // its AssetManager + skin-resolution bookkeeping) is reused + // verbatim. Reports per-file pass/fail and an aggregate + // summary. + // + // Designed to migrate an entire creature/world model dump + // in one go. Pair with --convert-blp-batch and --convert- + // wmo-batch to migrate a complete extracted Data tree. + std::string srcDir = argv[++i]; + namespace fs = std::filesystem; + if (!fs::exists(srcDir) || !fs::is_directory(srcDir)) { + std::fprintf(stderr, + "convert-m2-batch: %s is not a directory\n", + srcDir.c_str()); + return 1; + } + std::vector m2Files; + std::error_code ec; + for (const auto& e : fs::recursive_directory_iterator(srcDir, ec)) { + if (!e.is_regular_file()) continue; + std::string ext = e.path().extension().string(); + std::transform(ext.begin(), ext.end(), ext.begin(), + [](unsigned char c) { return std::tolower(c); }); + if (ext != ".m2") continue; + m2Files.push_back(e.path().string()); + } + std::sort(m2Files.begin(), m2Files.end()); + std::printf("convert-m2-batch: %s\n", srcDir.c_str()); + std::printf(" candidates : %zu .m2 file(s)\n", m2Files.size()); + std::string self = argv[0]; + int ok = 0, failed = 0; + for (const auto& m2 : m2Files) { + std::fflush(stdout); + std::string cmd = "\"" + self + "\" --convert-m2 \"" + m2 + "\""; + cmd += " >/dev/null 2>&1"; + int rc = std::system(cmd.c_str()); + if (rc == 0) { + ok++; + std::printf(" [ok] %s\n", m2.c_str()); + } else { + failed++; + std::printf(" [FAIL] %s (rc=%d)\n", m2.c_str(), rc); + } + } + std::printf("\n summary : %d ok, %d failed (out of %zu)\n", + ok, failed, m2Files.size()); + return failed == 0 ? 0 : 1; } else if (std::strcmp(argv[i], "--repair-zone") == 0 && i + 1 < argc) { // Auto-fix the common manifest-vs-disk drift issues that // accumulate when a zone is hand-edited or partially copied: