diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index 33ca1d3f..4732c50d 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -31,6 +31,7 @@ static void printUsage(const char* argv0) { std::printf(" --convert-wmo Convert WMO building to WOB open format (no GUI)\n"); std::printf(" --list-zones List discovered custom zones and exit\n"); std::printf(" --scaffold-zone [tx ty] Create a blank zone in custom_zones// and exit\n"); + std::printf(" --build-woc Generate a WOC collision mesh from WHM/WOT and exit\n"); std::printf(" --validate Score zone open-format completeness and exit\n"); std::printf(" --info Print WOM file metadata (version, counts) and exit\n"); std::printf(" --info-wob Print WOB building metadata (groups, portals, doodads) and exit\n"); @@ -59,7 +60,7 @@ int main(int argc, char* argv[]) { "--data", "--info", "--info-wob", "--info-woc", "--info-wot", "--info-creatures", "--info-objects", "--info-quests", "--info-wcp", "--list-wcp", "--unpack-wcp", "--pack-wcp", - "--validate", "--scaffold-zone", + "--validate", "--scaffold-zone", "--build-woc", "--convert-m2", "--convert-wmo", }; for (int i = 1; i < argc; i++) { @@ -375,6 +376,36 @@ int main(int argc, char* argv[]) { std::printf(" quests.json : %s\n", v.hasQuests ? "yes" : "no"); std::printf(" objects.json : %s\n", v.hasObjects ? "yes" : "no"); return score == 7 ? 0 : 1; + } else if (std::strcmp(argv[i], "--build-woc") == 0 && i + 1 < argc) { + // Generate a WOC collision mesh from a WHM/WOT terrain pair. + // Uses terrain triangles only (no WMO overlays); useful as a + // first-pass collision build before the editor adds buildings. + std::string base = argv[++i]; + for (const char* ext : {".wot", ".whm", ".woc"}) { + if (base.size() >= 4 && base.substr(base.size() - 4) == ext) { + base = base.substr(0, base.size() - 4); + break; + } + } + if (!wowee::pipeline::WoweeTerrainLoader::exists(base)) { + std::fprintf(stderr, "WOT/WHM not found at base: %s\n", base.c_str()); + return 1; + } + wowee::pipeline::ADTTerrain terrain; + if (!wowee::pipeline::WoweeTerrainLoader::load(base, terrain)) { + std::fprintf(stderr, "Failed to load terrain: %s\n", base.c_str()); + return 1; + } + auto col = wowee::pipeline::WoweeCollisionBuilder::fromTerrain(terrain); + std::string outPath = base + ".woc"; + if (!wowee::pipeline::WoweeCollisionBuilder::save(col, outPath)) { + std::fprintf(stderr, "WOC save failed: %s\n", outPath.c_str()); + return 1; + } + std::printf("WOC built: %s (%zu triangles, %zu walkable, %zu steep)\n", + outPath.c_str(), + col.triangles.size(), col.walkableCount(), col.steepCount()); + return 0; } else if (std::strcmp(argv[i], "--scaffold-zone") == 0 && i + 1 < argc) { // Generate a minimal valid empty zone — useful for kickstarting // a new authoring session without needing to launch the GUI.