mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-09 18:43:51 +00:00
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<Family> 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).
275 lines
11 KiB
C++
275 lines
11 KiB
C++
#include "cli_zone_packs.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
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<uint32_t>(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 <zoneDir>/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<std::string> args;
|
|
};
|
|
std::vector<Cmd> 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<int>(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 <zoneDir>/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<std::string> 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<MeshJob> 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<int>(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 <projectDir>,
|
|
// 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<std::string> 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<int>(ok1), static_cast<int>(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
|