From e02f2baf9d5bf806290cdcbfe0351a1e1431ce5b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 10:08:49 -0700 Subject: [PATCH] feat(editor): add --fix-zone CLI to re-apply load-time scrubs/caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loads + immediately re-saves zone.json, creatures.json, objects.json, and quests.json. The load-time scrubs (NaN, out-of-range, oversize) and save-time caps fire on the round-trip, producing a cleaned-up zone without ever opening the GUI. Useful when an old zone was created before recent hardening batches — running this once normalizes the on-disk state to match what the current loaders expect. --- tools/editor/main.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index 3c90c222..ec7bceae 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -33,6 +33,7 @@ static void printUsage(const char* argv0) { 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(" --regen-collision Rebuild every WOC under a zone dir and exit\n"); + std::printf(" --fix-zone Re-parse + re-save zone JSONs to apply latest scrubs/caps and exit\n"); std::printf(" --export-png Render heightmap, normal-map, and zone-map PNG previews\n"); std::printf(" --validate Score zone open-format completeness and exit\n"); std::printf(" --zone-summary One-shot validate + creature/object/quest counts and exit\n"); @@ -66,7 +67,8 @@ int main(int argc, char* argv[]) { "--info-creatures", "--info-objects", "--info-quests", "--info-zone", "--info-wcp", "--list-wcp", "--unpack-wcp", "--pack-wcp", "--validate", "--zone-summary", - "--scaffold-zone", "--build-woc", "--regen-collision", "--export-png", + "--scaffold-zone", "--build-woc", "--regen-collision", "--fix-zone", + "--export-png", "--convert-m2", "--convert-wmo", }; for (int i = 1; i < argc; i++) { @@ -553,6 +555,48 @@ int main(int argc, char* argv[]) { wowee::editor::WoweeTerrain::exportZoneMap(terrain, base + "_zone.png", 512); std::printf("Exported PNGs: %s_{heightmap,normals,zone}.png\n", base.c_str()); return 0; + } else if (std::strcmp(argv[i], "--fix-zone") == 0 && i + 1 < argc) { + // Re-parse + re-save every JSON/binary file in a zone to apply + // the editor's load-time scrubs and save-time caps. Useful when + // an old zone was created before recent hardening — running + // this once cleans up NaN/oversize fields without touching + // the editor GUI. + std::string zoneDir = argv[++i]; + namespace fs = std::filesystem; + if (!fs::exists(zoneDir)) { + std::fprintf(stderr, "fix-zone: %s does not exist\n", zoneDir.c_str()); + return 1; + } + int touched = 0; + // zone.json + { + wowee::editor::ZoneManifest m; + std::string p = zoneDir + "/zone.json"; + if (fs::exists(p) && m.load(p) && m.save(p)) touched++; + } + // creatures.json + { + wowee::editor::NpcSpawner sp; + std::string p = zoneDir + "/creatures.json"; + if (fs::exists(p) && sp.loadFromFile(p) && sp.saveToFile(p)) touched++; + } + // objects.json + { + wowee::editor::ObjectPlacer op; + std::string p = zoneDir + "/objects.json"; + if (fs::exists(p) && op.loadFromFile(p) && op.saveToFile(p)) touched++; + } + // quests.json + { + wowee::editor::QuestEditor qe; + std::string p = zoneDir + "/quests.json"; + if (fs::exists(p) && qe.loadFromFile(p) && qe.saveToFile(p)) touched++; + } + // WHM/WOT pairs and WoB files would need full pipeline access; + // skip them — the editor opens them on next zone load anyway, + // and the load-time scrubs run then. + std::printf("fix-zone: cleaned %d files in %s\n", touched, zoneDir.c_str()); + return 0; } else if (std::strcmp(argv[i], "--regen-collision") == 0 && i + 1 < argc) { // Find all WHM/WOT pairs under a zone dir and rebuild WOC for each. // Useful after sculpting changes when you want to re-derive