From facaacd0c623c700d13f405d8a4b58ab60f954ca Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 12:31:34 -0700 Subject: [PATCH] feat(editor): add --gen-blacksmith-pack + extract emitMeshPack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes in one commit because they're co-designed: • Extract emitMeshPack(outDir, packName, items) as a shared helper that takes a vector of PackItem {flag, fn, leaf} and runs each handler with a synthetic argv. Keeps the "build a 2-element argv per sub-handler" wiring in one place instead of copy-pasted per pack. • Add --gen-blacksmith-pack on top: a smithy-themed composite emitting forge + anvil + workbench + water-trough + crate-stack + hitching-post into outDir. The classic forge-floor layout in 6 .wom files. Refactors --gen-camp-pack to use emitMeshPack (verified unchanged: 6 .wom files still land in the camp dir). Pattern is now established for future packs (--gen-village- pack, --gen-temple-pack, --gen-dock-pack…) — each is just a list of primitives in 8 lines of code. --- tools/editor/cli_arg_required.cpp | 2 +- tools/editor/cli_gen_mesh.cpp | 101 ++++++++++++++++++------------ tools/editor/cli_help.cpp | 2 + 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index 8874eb87..1ffe107a 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -56,7 +56,7 @@ const char* const kArgRequired[] = { "--gen-mesh-watchpost", "--gen-mesh-water-trough", "--gen-mesh-training-dummy", "--gen-mesh-hitching-post", "--gen-mesh-outhouse", "--gen-mesh-forge", - "--gen-camp-pack", + "--gen-camp-pack", "--gen-blacksmith-pack", "--gen-mesh-table", "--gen-mesh-lamppost", "--gen-mesh-bed", "--gen-mesh-ladder", "--gen-mesh-well", "--gen-mesh-signpost", "--gen-mesh-mailbox", "--gen-mesh-tombstone", "--gen-mesh-crate", diff --git a/tools/editor/cli_gen_mesh.cpp b/tools/editor/cli_gen_mesh.cpp index 3a5ef639..7dca6fc6 100644 --- a/tools/editor/cli_gen_mesh.cpp +++ b/tools/editor/cli_gen_mesh.cpp @@ -6446,62 +6446,82 @@ int handleFirepit(int& i, int argc, char** argv) { return 0; } -int handleGenCampPack(int& i, int /*argc*/, char** argv) { - // Convenience composite: emit a complete outdoor-camp scene - // (tent, firepit, bedroll, canopy, woodpile, haystack) into - // in one command. Each primitive lands as its own - // .wom file using the existing handler — no per-primitive - // tweaking is exposed; users wanting custom dimensions should - // call the individual --gen-mesh-* commands directly. - std::string outDir = argv[++i]; +// Composite-pack item: a flag name, the handler that builds it, +// and the basename to write under . Used by --gen-camp-pack +// and --gen-blacksmith-pack to enumerate their member primitives. +struct PackItem { + const char* flag; + int (*fn)(int&, int, char**); + const char* leaf; +}; + +// Emit every PackItem in `items` into /. Returns 0 on full +// success or the first non-zero rc the handler produced. Each +// handler runs with a synthetic argv whose index 0 is the flag and +// index 1 is the destination wom-base — handlers do argv[++i] from +// the flag's position to read that base, so this matches the normal +// CLI invocation contract exactly. +int emitMeshPack(const std::string& outDir, const char* packName, + const std::vector& items) { std::error_code ec; std::filesystem::create_directories(outDir, ec); if (ec) { std::fprintf(stderr, - "gen-camp-pack: cannot create %s: %s\n", - outDir.c_str(), ec.message().c_str()); + "%s: cannot create %s: %s\n", + packName, outDir.c_str(), ec.message().c_str()); return 1; } - auto invoke = [&](int (*fn)(int&, int, char**), - const char* flag, const std::string& path) -> int { - // Build a synthetic argv where index 0 = the flag name and - // index 1 = the wom-base path (handlers do argv[++i] from - // the flag's position to read the base). - const char* args[2]; - args[0] = flag; - args[1] = path.c_str(); + int produced = 0; + for (const auto& it : items) { + std::string path = outDir + "/" + it.leaf; + const char* args[2] = {it.flag, path.c_str()}; std::vector mut; mut.reserve(2); for (auto* a : args) mut.push_back(const_cast(a)); int idx = 0; - return fn(idx, 2, mut.data()); - }; - struct Item { - const char* flag; - int (*fn)(int&, int, char**); - const char* leaf; - }; - const Item items[] = { + if (it.fn(idx, 2, mut.data()) != 0) { + std::fprintf(stderr, + "%s: %s sub-handler failed\n", packName, it.flag); + return 1; + } + ++produced; + } + std::printf("\nWrote %s to %s/ — %d primitives\n", + packName, outDir.c_str(), produced); + return 0; +} + +int handleGenCampPack(int& i, int /*argc*/, char** argv) { + // Outdoor-camp scene: tent, firepit, bedroll, canopy, + // woodpile, haystack. See emitMeshPack for the synthetic-argv + // contract. Users wanting custom dimensions should call the + // individual --gen-mesh-* commands directly. + std::string outDir = argv[++i]; + return emitMeshPack(outDir, "camp pack", { {"--gen-mesh-tent", handleTent, "tent"}, {"--gen-mesh-firepit", handleFirepit, "firepit"}, {"--gen-mesh-bedroll", handleBedroll, "bedroll"}, {"--gen-mesh-canopy", handleCanopy, "canopy"}, {"--gen-mesh-woodpile", handleWoodpile, "woodpile"}, {"--gen-mesh-haystack", handleHaystack, "haystack"}, - }; - int produced = 0; - for (const auto& it : items) { - std::string path = outDir + "/" + it.leaf; - if (invoke(it.fn, it.flag, path) != 0) { - std::fprintf(stderr, - "gen-camp-pack: %s sub-handler failed\n", it.flag); - return 1; - } - ++produced; - } - std::printf("\nWrote camp pack to %s/ — %d primitives\n", - outDir.c_str(), produced); - return 0; + }); +} + +int handleGenBlacksmithPack(int& i, int /*argc*/, char** argv) { + // Blacksmith / smithy scene: forge (the hot work), anvil + // (where iron gets struck), workbench (where finished tools + // land), water-trough (for tempering hot metal), crate-stack + // (for raw-material storage), hitching-post (for delivery + // mounts that drop off charcoal and ore). + std::string outDir = argv[++i]; + return emitMeshPack(outDir, "blacksmith pack", { + {"--gen-mesh-forge", handleForge, "forge"}, + {"--gen-mesh-anvil", handleAnvil, "anvil"}, + {"--gen-mesh-workbench", handleWorkbench, "workbench"}, + {"--gen-mesh-water-trough", handleWaterTrough, "trough"}, + {"--gen-mesh-crate-stack", handleCrateStack, "crates"}, + {"--gen-mesh-hitching-post", handleHitchingPost, "hitching"}, + }); } } // namespace @@ -6574,6 +6594,7 @@ constexpr MeshEntry kMeshTable[] = { {"--gen-mesh-outhouse", 1, handleOuthouse}, {"--gen-mesh-forge", 1, handleForge}, {"--gen-camp-pack", 1, handleGenCampPack}, + {"--gen-blacksmith-pack", 1, handleGenBlacksmithPack}, {"--gen-mesh-table", 1, handleTable}, {"--gen-mesh-lamppost", 1, handleLamppost}, {"--gen-mesh-bed", 1, handleBed}, diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index 2b51c185..c60be41a 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -268,6 +268,8 @@ void printUsage(const char* argv0) { std::printf(" Blacksmith forge: stone hearth + smaller hood + optional chimney (smithy / armorer set dressing)\n"); std::printf(" --gen-camp-pack \n"); std::printf(" Convenience: emit tent + firepit + bedroll + canopy + woodpile + haystack into outDir as 6 .wom files\n"); + std::printf(" --gen-blacksmith-pack \n"); + std::printf(" Convenience: emit forge + anvil + workbench + water-trough + crate-stack + hitching-post into outDir\n"); std::printf(" --gen-mesh-table [width] [depth] [height] [legThick] [topThick]\n"); std::printf(" Table: flat top slab on 4 corner legs (default 1.6/1.0/0.85/0.10/0.06)\n"); std::printf(" --gen-mesh-lamppost [poleH] [poleT] [baseSize] [lanternSize] [lanternH]\n");