From 81832ea6767888ba2f97a1dbc619762822387a5b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 08:19:42 -0700 Subject: [PATCH] feat(editor): add --pack-wcp CLI for headless zone packaging Mirrors --unpack-wcp. Accepts either a zone name (auto-resolved under custom_zones/ then output/) or a directory path. Default output is .wcp in the current directory. Combined with --scaffold-zone and --unpack-wcp, the editor can do the full zone authoring round-trip from the command line. --- tools/editor/main.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index c80f8559..33ca1d3f 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -41,6 +41,7 @@ static void printUsage(const char* argv0) { std::printf(" --info-quests

Print quests.json summary (counts, rewards, chain errors) and exit\n"); std::printf(" --info-wcp Print WCP archive metadata (name, files) and exit\n"); std::printf(" --list-wcp Print every file inside a WCP archive (sorted by path) and exit\n"); + std::printf(" --pack-wcp [dst] Pack a zone dir/name into a .wcp archive and exit\n"); std::printf(" --unpack-wcp [dst] Extract a WCP archive (default dst=custom_zones/) and exit\n"); std::printf(" --version Show version and format info\n\n"); std::printf("Wowee World Editor v1.0.0 — by Kelsi Davis\n"); @@ -57,7 +58,8 @@ int main(int argc, char* argv[]) { static const char* kArgRequired[] = { "--data", "--info", "--info-wob", "--info-woc", "--info-wot", "--info-creatures", "--info-objects", "--info-quests", - "--info-wcp", "--list-wcp", "--unpack-wcp", "--validate", "--scaffold-zone", + "--info-wcp", "--list-wcp", "--unpack-wcp", "--pack-wcp", + "--validate", "--scaffold-zone", "--convert-m2", "--convert-wmo", }; for (int i = 1; i < argc; i++) { @@ -433,6 +435,46 @@ int main(int argc, char* argv[]) { slug.c_str(), slug.c_str()); std::printf(" next step: run editor without args, then File → Open Zone\n"); return 0; + } else if (std::strcmp(argv[i], "--pack-wcp") == 0 && i + 1 < argc) { + // Pack a zone directory into a .wcp archive. + // Usage: --pack-wcp [destPath] + // If looks like a path (contains '/' or starts + // with '.'), use it directly; otherwise resolve under + // custom_zones/ then output/ (matching the discovery search + // order). + std::string nameOrDir = argv[++i]; + std::string destPath; + if (i + 1 < argc && argv[i + 1][0] != '-') { + destPath = argv[++i]; + } + namespace fs = std::filesystem; + std::string outputDir, mapName; + if (nameOrDir.find('/') != std::string::npos || nameOrDir[0] == '.') { + fs::path p = fs::absolute(nameOrDir); + outputDir = p.parent_path().string(); + mapName = p.filename().string(); + } else { + mapName = nameOrDir; + if (fs::exists("custom_zones/" + mapName)) outputDir = "custom_zones"; + else if (fs::exists("output/" + mapName)) outputDir = "output"; + else { + std::fprintf(stderr, + "--pack-wcp: zone '%s' not found in custom_zones/ or output/\n", + mapName.c_str()); + return 1; + } + } + if (destPath.empty()) destPath = mapName + ".wcp"; + wowee::editor::ContentPackInfo info; + info.name = mapName; + info.format = "wcp-1.0"; + if (!wowee::editor::ContentPacker::packZone(outputDir, mapName, destPath, info)) { + std::fprintf(stderr, "WCP pack failed for %s/%s\n", + outputDir.c_str(), mapName.c_str()); + return 1; + } + std::printf("WCP packed: %s\n", destPath.c_str()); + return 0; } else if (std::strcmp(argv[i], "--unpack-wcp") == 0 && i + 1 < argc) { std::string wcpPath = argv[++i]; std::string destDir = "custom_zones";