From 774dab933068447783f27fa82164574cd3bb0917 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 8 May 2026 16:46:14 -0700 Subject: [PATCH] refactor(editor): extract zone-pack orchestrators into cli_zone_packs.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continues the modularization started in 6c9ab6fa. Moves the four pack-orchestrator handlers (--gen-zone-texture-pack, -mesh-pack, -starter-pack, --gen-project-starter-pack) into their own file following the same handle pattern. Side cleanup: - Consolidated the duplicated --seed flag parser into a single parseSeedFlag helper - Consolidated the std::system + > /dev/null wrap into runSilently main.cpp drops 28,329 → 28,070 lines (-259). Pack family is fully self-contained (~260 lines), behavior unchanged (verified by re-running gen-zone-starter-pack and confirming 6 PNGs + 5 WOMs). --- CMakeLists.txt | 1 + tools/editor/cli_zone_packs.cpp | 275 ++++++++++++++++++++++++++++++++ tools/editor/cli_zone_packs.hpp | 22 +++ tools/editor/main.cpp | 267 +------------------------------ 4 files changed, 302 insertions(+), 263 deletions(-) create mode 100644 tools/editor/cli_zone_packs.cpp create mode 100644 tools/editor/cli_zone_packs.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 20355aae..8debe8e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1299,6 +1299,7 @@ install(TARGETS blp_convert RUNTIME DESTINATION bin) add_executable(wowee_editor tools/editor/main.cpp tools/editor/cli_gen_audio.cpp + tools/editor/cli_zone_packs.cpp tools/editor/editor_app.cpp tools/editor/editor_camera.cpp tools/editor/editor_viewport.cpp diff --git a/tools/editor/cli_zone_packs.cpp b/tools/editor/cli_zone_packs.cpp new file mode 100644 index 00000000..83692ef0 --- /dev/null +++ b/tools/editor/cli_zone_packs.cpp @@ -0,0 +1,275 @@ +#include "cli_zone_packs.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace wowee { +namespace editor { +namespace cli { + +namespace { + +// Parse a trailing `--seed N` flag pair. Returns updated `i` past +// the consumed args via the by-ref param. Sets seed if found. +// Returns false if it sees an unknown --flag (caller should error). +bool parseSeedFlag(int& i, int argc, char** argv, + const char* cmdName, uint32_t& seed) { + for (int k = i + 1; k < argc; ++k) { + std::string flag = argv[k]; + if (flag == "--seed" && k + 1 < argc) { + try { seed = static_cast(std::stoul(argv[++k])); } + catch (...) {} + i = k; + } else if (flag.rfind("--", 0) == 0) { + std::fprintf(stderr, + "%s: unknown flag '%s'\n", cmdName, flag.c_str()); + return false; + } + } + return true; +} + +// Run a sub-process via std::system, log on failure, return rc==0. +bool runSilently(const std::string& cmd) { + std::string full = cmd + " > /dev/null 2>&1"; + return std::system(full.c_str()) == 0; +} + +int handleTexturePack(int& i, int argc, char** argv) { + // Drop a starter PNG texture pack into /textures/ + // by fanning out to the procedural --gen-texture-* commands. + // Saves the user from sourcing proprietary art when bringing + // up a new zone — six themed textures cover most needs. + std::string zoneDir = argv[++i]; + uint32_t seed = 1; + if (!parseSeedFlag(i, argc, argv, "gen-zone-texture-pack", seed)) return 1; + std::filesystem::path zp(zoneDir); + if (!std::filesystem::exists(zp / "zone.json")) { + std::fprintf(stderr, + "gen-zone-texture-pack: %s has no zone.json\n", zoneDir.c_str()); + return 1; + } + std::filesystem::path texDir = zp / "textures"; + std::error_code ec; + std::filesystem::create_directories(texDir, ec); + if (ec) { + std::fprintf(stderr, + "gen-zone-texture-pack: cannot create %s: %s\n", + texDir.string().c_str(), ec.message().c_str()); + return 1; + } + std::string self = (argc > 0) ? argv[0] : "wowee_editor"; + struct Cmd { + std::string flag; + std::string outName; + std::vector args; + }; + std::vector jobs = { + {"--gen-texture-noise", "grass.png", {"4A7C2E", "5C9B3A", "256", "256"}}, + {"--gen-texture-noise", "dirt.png", {"6B4A2A", "8B5E3A", "256", "256"}}, + {"--gen-texture-checker", "stone.png", {"7A7A7A", "5A5A5A", "32", "256", "256"}}, + {"--gen-texture-brick", "brick.png", {"8B4513", "D3D3D3", "64", "24", "4", "256", "256"}}, + {"--gen-texture-wood", "wood.png", {"8B5A2B", "4A3216", "12", std::to_string(seed), "256", "256"}}, + {"--gen-texture-radial", "water.png", {"3A6FA0", "1E4A78", "256", "256"}}, + }; + int written = 0; + for (const auto& job : jobs) { + std::filesystem::path out = texDir / job.outName; + std::string cmd = "\"" + self + "\" " + job.flag + " \"" + out.string() + "\""; + for (const auto& a : job.args) cmd += " " + a; + if (!runSilently(cmd)) { + std::fprintf(stderr, + "gen-zone-texture-pack: %s failed\n", job.flag.c_str()); + } else { + ++written; + } + } + std::printf("gen-zone-texture-pack: wrote %d of %zu textures to %s\n", + written, jobs.size(), texDir.string().c_str()); + return written == static_cast(jobs.size()) ? 0 : 1; +} + +int handleMeshPack(int& i, int argc, char** argv) { + // Companion to --gen-zone-texture-pack: drops a starter + // WOM mesh pack into /meshes/. Each rock variant + // uses a different seed so they read as distinct boulders. + std::string zoneDir = argv[++i]; + uint32_t seed = 1; + if (!parseSeedFlag(i, argc, argv, "gen-zone-mesh-pack", seed)) return 1; + std::filesystem::path zp(zoneDir); + if (!std::filesystem::exists(zp / "zone.json")) { + std::fprintf(stderr, + "gen-zone-mesh-pack: %s has no zone.json\n", zoneDir.c_str()); + return 1; + } + std::filesystem::path meshDir = zp / "meshes"; + std::error_code ec; + std::filesystem::create_directories(meshDir, ec); + if (ec) { + std::fprintf(stderr, + "gen-zone-mesh-pack: cannot create %s: %s\n", + meshDir.string().c_str(), ec.message().c_str()); + return 1; + } + std::string self = (argc > 0) ? argv[0] : "wowee_editor"; + struct MeshJob { + std::string flag; + std::string outBase; // no .wom extension + std::vector args; + }; + std::string s0 = std::to_string(seed); + std::string s1 = std::to_string(seed + 17); + std::string s2 = std::to_string(seed + 41); + std::vector jobs = { + // 3 rock variants with distinct seeds for variety + {"--gen-mesh-rock", "rock_small", {"0.6", "0.30", "2", s0}}, + {"--gen-mesh-rock", "rock_medium", {"1.2", "0.25", "2", s1}}, + {"--gen-mesh-rock", "rock_large", {"2.4", "0.35", "3", s2}}, + // Tree placeholder, fence segment for boundaries + {"--gen-mesh-tree", "tree", {"0.15", "3.0", "1.0"}}, + {"--gen-mesh-fence", "fence", {"5", "1.2", "1.4", "0.06"}}, + }; + int written = 0; + for (const auto& job : jobs) { + std::filesystem::path out = meshDir / job.outBase; + std::string cmd = "\"" + self + "\" " + job.flag + " \"" + out.string() + "\""; + for (const auto& a : job.args) cmd += " " + a; + if (!runSilently(cmd)) { + std::fprintf(stderr, + "gen-zone-mesh-pack: %s failed\n", job.flag.c_str()); + } else { + ++written; + } + } + std::printf("gen-zone-mesh-pack: wrote %d of %zu meshes to %s\n", + written, jobs.size(), meshDir.string().c_str()); + return written == static_cast(jobs.size()) ? 0 : 1; +} + +int handleZoneStarterPack(int& i, int argc, char** argv) { + // Convenience entry point: run --gen-zone-texture-pack + // and --gen-zone-mesh-pack in sequence so a fresh zone + // gets a full open-format asset bootstrap from a single + // command. Seed propagates to both children. + std::string zoneDir = argv[++i]; + uint32_t seed = 1; + if (!parseSeedFlag(i, argc, argv, "gen-zone-starter-pack", seed)) return 1; + if (!std::filesystem::exists(std::filesystem::path(zoneDir) / "zone.json")) { + std::fprintf(stderr, + "gen-zone-starter-pack: %s has no zone.json\n", zoneDir.c_str()); + return 1; + } + std::string self = (argc > 0) ? argv[0] : "wowee_editor"; + std::string seedStr = std::to_string(seed); + std::printf("gen-zone-starter-pack: %s (seed %u)\n", + zoneDir.c_str(), seed); + std::printf(" step 1/2: textures\n"); + std::string cmd1 = "\"" + self + "\" --gen-zone-texture-pack \"" + + zoneDir + "\" --seed " + seedStr; + if (std::system(cmd1.c_str()) != 0) { + std::fprintf(stderr, "gen-zone-starter-pack: texture step failed\n"); + return 1; + } + std::printf(" step 2/2: meshes\n"); + std::string cmd2 = "\"" + self + "\" --gen-zone-mesh-pack \"" + + zoneDir + "\" --seed " + seedStr; + if (std::system(cmd2.c_str()) != 0) { + std::fprintf(stderr, "gen-zone-starter-pack: mesh step failed\n"); + return 1; + } + std::printf("\ngen-zone-starter-pack: complete\n"); + std::printf(" zone dir : %s\n", zoneDir.c_str()); + std::printf(" textures : 6 PNGs in textures/\n"); + std::printf(" meshes : 5 WOMs in meshes/\n"); + return 0; +} + +int handleProjectStarterPack(int& i, int argc, char** argv) { + // Project-wide bootstrap. For every zone in , + // run --gen-zone-starter-pack (textures + meshes) and + // --gen-zone-audio-pack (audio). Each zone gets a unique + // sub-seed offset from the base seed so per-zone content + // looks distinct. + std::string projectDir = argv[++i]; + uint32_t seed = 1; + if (!parseSeedFlag(i, argc, argv, "gen-project-starter-pack", seed)) return 1; + namespace fs = std::filesystem; + if (!fs::exists(projectDir) || !fs::is_directory(projectDir)) { + std::fprintf(stderr, + "gen-project-starter-pack: %s is not a directory\n", + projectDir.c_str()); + return 1; + } + std::vector zones; + for (const auto& entry : fs::directory_iterator(projectDir)) { + if (!entry.is_directory()) continue; + if (!fs::exists(entry.path() / "zone.json")) continue; + zones.push_back(entry.path().string()); + } + std::sort(zones.begin(), zones.end()); + if (zones.empty()) { + std::fprintf(stderr, + "gen-project-starter-pack: %s contains no zones\n", + projectDir.c_str()); + return 1; + } + std::string self = (argc > 0) ? argv[0] : "wowee_editor"; + std::printf("gen-project-starter-pack: %s (base seed %u)\n", + projectDir.c_str(), seed); + std::printf(" zones: %zu\n\n", zones.size()); + int passed = 0, failed = 0; + for (size_t z = 0; z < zones.size(); ++z) { + std::string zoneSeed = std::to_string(seed + z * 17); + std::string name = fs::path(zones[z]).filename().string(); + std::printf(" [%zu/%zu] %s (seed %s)\n", + z + 1, zones.size(), name.c_str(), zoneSeed.c_str()); + std::string c1 = "\"" + self + "\" --gen-zone-starter-pack \"" + + zones[z] + "\" --seed " + zoneSeed; + bool ok1 = runSilently(c1); + std::string c2 = "\"" + self + "\" --gen-zone-audio-pack \"" + + zones[z] + "\""; + bool ok2 = runSilently(c2); + if (ok1 && ok2) { + ++passed; + std::printf(" OK textures + meshes + audio\n"); + } else { + ++failed; + std::printf(" FAIL starter ok=%d, audio ok=%d\n", + static_cast(ok1), static_cast(ok2)); + } + } + std::printf("\n Total: %d passed, %d failed\n", passed, failed); + return failed == 0 ? 0 : 1; +} + +} // namespace + +bool handleZonePacks(int& i, int argc, char** argv, int& outRc) { + if (std::strcmp(argv[i], "--gen-zone-texture-pack") == 0 && i + 1 < argc) { + outRc = handleTexturePack(i, argc, argv); + return true; + } + if (std::strcmp(argv[i], "--gen-zone-mesh-pack") == 0 && i + 1 < argc) { + outRc = handleMeshPack(i, argc, argv); + return true; + } + if (std::strcmp(argv[i], "--gen-zone-starter-pack") == 0 && i + 1 < argc) { + outRc = handleZoneStarterPack(i, argc, argv); + return true; + } + if (std::strcmp(argv[i], "--gen-project-starter-pack") == 0 && i + 1 < argc) { + outRc = handleProjectStarterPack(i, argc, argv); + return true; + } + return false; +} + +} // namespace cli +} // namespace editor +} // namespace wowee diff --git a/tools/editor/cli_zone_packs.hpp b/tools/editor/cli_zone_packs.hpp new file mode 100644 index 00000000..54503cea --- /dev/null +++ b/tools/editor/cli_zone_packs.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace wowee { +namespace editor { +namespace cli { + +// Dispatch the four zone/project pack-orchestrator handlers: +// --gen-zone-texture-pack +// --gen-zone-mesh-pack +// --gen-zone-starter-pack +// --gen-project-starter-pack +// +// Each fans out to per-asset commands via subprocess, so this +// module has no dependency on the procedural generators it calls. +// +// Returns true if matched; outRc holds the exit code. Returns +// false if no match — caller should continue its dispatch chain. +bool handleZonePacks(int& i, int argc, char** argv, int& outRc); + +} // namespace cli +} // namespace editor +} // namespace wowee diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index ed0d95ae..15f1ce98 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -1,5 +1,6 @@ #include "editor_app.hpp" #include "cli_gen_audio.hpp" +#include "cli_zone_packs.hpp" #include "content_pack.hpp" #include "npc_spawner.hpp" #include "object_placer.hpp" @@ -1365,6 +1366,9 @@ int main(int argc, char* argv[]) { if (wowee::editor::cli::handleGenAudio(i, argc, argv, outRc)) { return outRc; } + if (wowee::editor::cli::handleZonePacks(i, argc, argv, outRc)) { + return outRc; + } } if (std::strcmp(argv[i], "--data") == 0 && i + 1 < argc) { dataPath = argv[++i]; @@ -14397,269 +14401,6 @@ int main(int argc, char* argv[]) { std::printf(" objects : %d\n", objects); std::printf(" items : %d\n", items); return 0; - } else if (std::strcmp(argv[i], "--gen-zone-texture-pack") == 0 && i + 1 < argc) { - // Drop a starter PNG texture pack into /textures/ - // by fanning out to the procedural --gen-texture-* commands. - // Saves the user from sourcing proprietary art when bringing - // up a new zone — six themed textures (grass, dirt, stone, - // brick, wood, water) cover most outdoor & dungeon needs. - std::string zoneDir = argv[++i]; - uint32_t seed = 1; - for (int k = i + 1; k < argc; ++k) { - std::string flag = argv[k]; - if (flag == "--seed" && k + 1 < argc) { - try { seed = static_cast(std::stoul(argv[++k])); } catch (...) {} - i = k; - } else if (flag.rfind("--", 0) == 0) { - std::fprintf(stderr, - "gen-zone-texture-pack: unknown flag '%s'\n", flag.c_str()); - return 1; - } - } - std::filesystem::path zp(zoneDir); - if (!std::filesystem::exists(zp / "zone.json")) { - std::fprintf(stderr, - "gen-zone-texture-pack: %s has no zone.json\n", - zoneDir.c_str()); - return 1; - } - std::filesystem::path texDir = zp / "textures"; - std::error_code ec; - std::filesystem::create_directories(texDir, ec); - if (ec) { - std::fprintf(stderr, - "gen-zone-texture-pack: cannot create %s: %s\n", - texDir.string().c_str(), ec.message().c_str()); - return 1; - } - std::string self = (argc > 0) ? argv[0] : "wowee_editor"; - // Each row: {flag, fileName, args...}. Using std::string so - // we can interpolate the per-pack seed without sprintf - // gymnastics; subprocess invocation handles quoting. - struct Cmd { - std::string flag; - std::string outName; - std::vector args; - }; - std::vector jobs = { - {"--gen-texture-noise", "grass.png", {"4A7C2E", "5C9B3A", "256", "256"}}, - {"--gen-texture-noise", "dirt.png", {"6B4A2A", "8B5E3A", "256", "256"}}, - {"--gen-texture-checker", "stone.png", {"7A7A7A", "5A5A5A", "32", "256", "256"}}, - {"--gen-texture-brick", "brick.png", {"8B4513", "D3D3D3", "64", "24", "4", "256", "256"}}, - {"--gen-texture-wood", "wood.png", {"8B5A2B", "4A3216", "12", std::to_string(seed), "256", "256"}}, - {"--gen-texture-radial", "water.png", {"3A6FA0", "1E4A78", "256", "256"}}, - }; - int written = 0; - for (const auto& job : jobs) { - std::filesystem::path out = texDir / job.outName; - std::string cmd = "\"" + self + "\" " + job.flag + " \"" + out.string() + "\""; - for (const auto& a : job.args) cmd += " " + a; - cmd += " > /dev/null 2>&1"; - int rc = std::system(cmd.c_str()); - if (rc != 0) { - std::fprintf(stderr, - "gen-zone-texture-pack: %s failed (rc=%d)\n", - job.flag.c_str(), rc); - } else { - ++written; - } - } - std::printf("gen-zone-texture-pack: wrote %d of %zu textures to %s\n", - written, jobs.size(), texDir.string().c_str()); - return written == static_cast(jobs.size()) ? 0 : 1; - } else if (std::strcmp(argv[i], "--gen-zone-mesh-pack") == 0 && i + 1 < argc) { - // Companion to --gen-zone-texture-pack: drops a starter - // WOM mesh pack into /meshes/. Bootstraps the - // mesh side of the open-format pipeline so a fresh zone - // has placeholders for outdoor decoration without any - // proprietary M2 imports. Each rock variant uses a - // different seed so they read as distinct boulders. - std::string zoneDir = argv[++i]; - uint32_t seed = 1; - for (int k = i + 1; k < argc; ++k) { - std::string flag = argv[k]; - if (flag == "--seed" && k + 1 < argc) { - try { seed = static_cast(std::stoul(argv[++k])); } catch (...) {} - i = k; - } else if (flag.rfind("--", 0) == 0) { - std::fprintf(stderr, - "gen-zone-mesh-pack: unknown flag '%s'\n", flag.c_str()); - return 1; - } - } - std::filesystem::path zp(zoneDir); - if (!std::filesystem::exists(zp / "zone.json")) { - std::fprintf(stderr, - "gen-zone-mesh-pack: %s has no zone.json\n", - zoneDir.c_str()); - return 1; - } - std::filesystem::path meshDir = zp / "meshes"; - std::error_code ec; - std::filesystem::create_directories(meshDir, ec); - if (ec) { - std::fprintf(stderr, - "gen-zone-mesh-pack: cannot create %s: %s\n", - meshDir.string().c_str(), ec.message().c_str()); - return 1; - } - std::string self = (argc > 0) ? argv[0] : "wowee_editor"; - struct MeshJob { - std::string flag; - std::string outBase; // no .wom extension - std::vector args; - }; - std::string s0 = std::to_string(seed); - std::string s1 = std::to_string(seed + 17); - std::string s2 = std::to_string(seed + 41); - std::vector jobs = { - // 3 rock variants with distinct seeds for variety - {"--gen-mesh-rock", "rock_small", {"0.6", "0.30", "2", s0}}, - {"--gen-mesh-rock", "rock_medium", {"1.2", "0.25", "2", s1}}, - {"--gen-mesh-rock", "rock_large", {"2.4", "0.35", "3", s2}}, - // Tree placeholder, fence segment for boundaries - {"--gen-mesh-tree", "tree", {"0.15", "3.0", "1.0"}}, - {"--gen-mesh-fence", "fence", {"5", "1.2", "1.4", "0.06"}}, - }; - int written = 0; - for (const auto& job : jobs) { - std::filesystem::path out = meshDir / job.outBase; - std::string cmd = "\"" + self + "\" " + job.flag + " \"" + out.string() + "\""; - for (const auto& a : job.args) cmd += " " + a; - cmd += " > /dev/null 2>&1"; - int rc = std::system(cmd.c_str()); - if (rc != 0) { - std::fprintf(stderr, - "gen-zone-mesh-pack: %s failed (rc=%d)\n", - job.flag.c_str(), rc); - } else { - ++written; - } - } - std::printf("gen-zone-mesh-pack: wrote %d of %zu meshes to %s\n", - written, jobs.size(), meshDir.string().c_str()); - return written == static_cast(jobs.size()) ? 0 : 1; - } else if (std::strcmp(argv[i], "--gen-zone-starter-pack") == 0 && i + 1 < argc) { - // Convenience entry point: run --gen-zone-texture-pack - // and --gen-zone-mesh-pack in sequence so a fresh zone - // gets a full open-format asset bootstrap from a single - // command. The seed propagates to both children so a - // user can reliably reproduce the same starter pack. - std::string zoneDir = argv[++i]; - uint32_t seed = 1; - for (int k = i + 1; k < argc; ++k) { - std::string flag = argv[k]; - if (flag == "--seed" && k + 1 < argc) { - try { seed = static_cast(std::stoul(argv[++k])); } catch (...) {} - i = k; - } else if (flag.rfind("--", 0) == 0) { - std::fprintf(stderr, - "gen-zone-starter-pack: unknown flag '%s'\n", flag.c_str()); - return 1; - } - } - if (!std::filesystem::exists(std::filesystem::path(zoneDir) / "zone.json")) { - std::fprintf(stderr, - "gen-zone-starter-pack: %s has no zone.json\n", - zoneDir.c_str()); - return 1; - } - std::string self = (argc > 0) ? argv[0] : "wowee_editor"; - std::string seedStr = std::to_string(seed); - std::printf("gen-zone-starter-pack: %s (seed %u)\n", - zoneDir.c_str(), seed); - std::printf(" step 1/2: textures\n"); - std::string cmd1 = "\"" + self + "\" --gen-zone-texture-pack \"" + - zoneDir + "\" --seed " + seedStr; - int rc1 = std::system(cmd1.c_str()); - if (rc1 != 0) { - std::fprintf(stderr, - "gen-zone-starter-pack: texture step failed (rc=%d)\n", rc1); - return 1; - } - std::printf(" step 2/2: meshes\n"); - std::string cmd2 = "\"" + self + "\" --gen-zone-mesh-pack \"" + - zoneDir + "\" --seed " + seedStr; - int rc2 = std::system(cmd2.c_str()); - if (rc2 != 0) { - std::fprintf(stderr, - "gen-zone-starter-pack: mesh step failed (rc=%d)\n", rc2); - return 1; - } - std::printf("\ngen-zone-starter-pack: complete\n"); - std::printf(" zone dir : %s\n", zoneDir.c_str()); - std::printf(" textures : 6 PNGs in textures/\n"); - std::printf(" meshes : 5 WOMs in meshes/\n"); - return 0; - } else if (std::strcmp(argv[i], "--gen-project-starter-pack") == 0 && i + 1 < argc) { - // Project-wide bootstrap. For every zone in , - // run --gen-zone-starter-pack (textures + meshes) and - // --gen-zone-audio-pack (audio). Each zone gets a unique - // sub-seed offset from the base seed so per-zone content - // looks distinct (e.g. rocks differ, wood grain differs). - // - // Pairs with --validate-project-packs as the inverse — - // bootstrap, then audit, then ship. - std::string projectDir = argv[++i]; - uint32_t seed = 1; - for (int k = i + 1; k < argc; ++k) { - std::string flag = argv[k]; - if (flag == "--seed" && k + 1 < argc) { - try { seed = static_cast(std::stoul(argv[++k])); } catch (...) {} - i = k; - } else if (flag.rfind("--", 0) == 0) { - std::fprintf(stderr, - "gen-project-starter-pack: unknown flag '%s'\n", flag.c_str()); - return 1; - } - } - namespace fs = std::filesystem; - if (!fs::exists(projectDir) || !fs::is_directory(projectDir)) { - std::fprintf(stderr, - "gen-project-starter-pack: %s is not a directory\n", - projectDir.c_str()); - return 1; - } - std::vector zones; - for (const auto& entry : fs::directory_iterator(projectDir)) { - if (!entry.is_directory()) continue; - if (!fs::exists(entry.path() / "zone.json")) continue; - zones.push_back(entry.path().string()); - } - std::sort(zones.begin(), zones.end()); - if (zones.empty()) { - std::fprintf(stderr, - "gen-project-starter-pack: %s contains no zones\n", - projectDir.c_str()); - return 1; - } - std::string self = (argc > 0) ? argv[0] : "wowee_editor"; - std::printf("gen-project-starter-pack: %s (base seed %u)\n", - projectDir.c_str(), seed); - std::printf(" zones: %zu\n\n", zones.size()); - int passed = 0, failed = 0; - for (size_t z = 0; z < zones.size(); ++z) { - std::string zoneSeed = std::to_string(seed + z * 17); - std::string name = fs::path(zones[z]).filename().string(); - std::printf(" [%zu/%zu] %s (seed %s)\n", - z + 1, zones.size(), name.c_str(), zoneSeed.c_str()); - std::string c1 = "\"" + self + "\" --gen-zone-starter-pack \"" + - zones[z] + "\" --seed " + zoneSeed + - " > /dev/null 2>&1"; - int rc1 = std::system(c1.c_str()); - std::string c2 = "\"" + self + "\" --gen-zone-audio-pack \"" + - zones[z] + "\" > /dev/null 2>&1"; - int rc2 = std::system(c2.c_str()); - if (rc1 == 0 && rc2 == 0) { - ++passed; - std::printf(" OK textures + meshes + audio\n"); - } else { - ++failed; - std::printf(" FAIL starter rc=%d, audio rc=%d\n", rc1, rc2); - } - } - std::printf("\n Total: %d passed, %d failed\n", passed, failed); - return failed == 0 ? 0 : 1; } else if (std::strcmp(argv[i], "--info-zone-summary") == 0 && i + 1 < argc) { // One-glance health digest for a zone. Combines the per- // category counts/bytes from the inventory commands with