From 65d867c035685cf01b6596d5af42af57b28af5e0 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 11:27:53 -0700 Subject: [PATCH] feat(editor): --json mode on --info-wot and --info-zone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last two inspectors to gain --json mode. Schemas show off the nested structure these commands surface (chunk counts, audio sub-object, tile array): --info-wot → { base, tileX, tileY, chunks: { withHeightmap, withLayers, withWater }, textures, doodads, wmos, heightMin, heightMax } --info-zone → { file, mapName, displayName, mapId, biome, baseHeight, hasCreatures, description, tiles: [[x,y], ...], flags: { allowFlying, pvpEnabled, isIndoor, isSanctuary }, audio?: { music, musicVolume, ambienceDay, ambienceVolume, ambienceNight } } Every CLI inspector in the wowee_editor binary now supports --json. Total: 14 commands with machine-readable output (extract/zone/wcp inspectors, validate, diff-wcp, list-zones, info-wom/wob/woc/wot/ zone/creatures/objects/quests, zone-summary). --- tools/editor/main.cpp | 65 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index 4ba11da2..1dab0b43 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -46,10 +46,12 @@ static void printUsage(const char* argv0) { std::printf(" Print WOB building metadata (groups, portals, doodads) and exit\n"); std::printf(" --info-woc [--json]\n"); std::printf(" Print WOC collision metadata (triangle counts, bounds) and exit\n"); - std::printf(" --info-wot Print WOT/WHM terrain metadata (tile, chunks, height range) and exit\n"); + std::printf(" --info-wot [--json]\n"); + std::printf(" Print WOT/WHM terrain metadata (tile, chunks, height range) and exit\n"); std::printf(" --info-extract [--json]\n"); std::printf(" Walk extracted asset tree and report open-format coverage and exit\n"); - std::printf(" --info-zone Print zone.json fields (manifest, tiles, audio, flags) and exit\n"); + std::printf(" --info-zone [--json]\n"); + std::printf(" Print zone.json fields (manifest, tiles, audio, flags) and exit\n"); std::printf(" --info-creatures

[--json]\n"); std::printf(" Print creatures.json summary (counts, behaviors) and exit\n"); std::printf(" --info-objects

[--json]\n"); @@ -420,6 +422,9 @@ int main(int argc, char* argv[]) { // diffing two zones or auditing the audio/flag setup before // packing into a WCP. std::string zonePath = argv[++i]; + bool jsonOut = (i + 1 < argc && + std::strcmp(argv[i + 1], "--json") == 0); + if (jsonOut) i++; namespace fs = std::filesystem; // Accept either a directory or the zone.json itself. if (fs::is_directory(zonePath)) zonePath += "/zone.json"; @@ -428,6 +433,41 @@ int main(int argc, char* argv[]) { std::fprintf(stderr, "Failed to load zone.json: %s\n", zonePath.c_str()); return 1; } + if (jsonOut) { + nlohmann::json j; + j["file"] = zonePath; + j["mapName"] = manifest.mapName; + j["displayName"] = manifest.displayName; + j["mapId"] = manifest.mapId; + j["biome"] = manifest.biome; + j["baseHeight"] = manifest.baseHeight; + j["hasCreatures"] = manifest.hasCreatures; + j["description"] = manifest.description; + nlohmann::json tilesArr = nlohmann::json::array(); + for (const auto& t : manifest.tiles) + tilesArr.push_back({t.first, t.second}); + j["tiles"] = tilesArr; + j["flags"] = {{"allowFlying", manifest.allowFlying}, + {"pvpEnabled", manifest.pvpEnabled}, + {"isIndoor", manifest.isIndoor}, + {"isSanctuary", manifest.isSanctuary}}; + if (!manifest.musicTrack.empty() || !manifest.ambienceDay.empty()) { + nlohmann::json audio; + if (!manifest.musicTrack.empty()) { + audio["music"] = manifest.musicTrack; + audio["musicVolume"] = manifest.musicVolume; + } + if (!manifest.ambienceDay.empty()) { + audio["ambienceDay"] = manifest.ambienceDay; + audio["ambienceVolume"] = manifest.ambienceVolume; + } + if (!manifest.ambienceNight.empty()) + audio["ambienceNight"] = manifest.ambienceNight; + j["audio"] = audio; + } + std::printf("%s\n", j.dump(2).c_str()); + return 0; + } std::printf("zone.json: %s\n", zonePath.c_str()); std::printf(" mapName : %s\n", manifest.mapName.c_str()); std::printf(" displayName : %s\n", manifest.displayName.c_str()); @@ -652,6 +692,9 @@ int main(int argc, char* argv[]) { return 0; } else if (std::strcmp(argv[i], "--info-wot") == 0 && i + 1 < argc) { std::string base = argv[++i]; + bool jsonOut = (i + 1 < argc && + std::strcmp(argv[i + 1], "--json") == 0); + if (jsonOut) i++; // Accept "/path/file.wot", "/path/file.whm", or "/path/file"; the // loader pairs both extensions from the same base path. for (const char* ext : {".wot", ".whm"}) { @@ -684,6 +727,24 @@ int main(int argc, char* argv[]) { if (!c.layers.empty()) chunksWithLayers++; if (terrain.waterData[ci].hasWater()) chunksWithWater++; } + if (jsonOut) { + nlohmann::json j; + j["base"] = base; + j["tileX"] = terrain.coord.x; + j["tileY"] = terrain.coord.y; + j["chunks"] = {{"withHeightmap", chunksWithHeights}, + {"withLayers", chunksWithLayers}, + {"withWater", chunksWithWater}}; + j["textures"] = terrain.textures.size(); + j["doodads"] = terrain.doodadPlacements.size(); + j["wmos"] = terrain.wmoPlacements.size(); + if (chunksWithHeights > 0) { + j["heightMin"] = minH; + j["heightMax"] = maxH; + } + std::printf("%s\n", j.dump(2).c_str()); + return 0; + } std::printf("WOT/WHM: %s\n", base.c_str()); std::printf(" tile : (%d, %d)\n", terrain.coord.x, terrain.coord.y); std::printf(" chunks : %d/256 with heightmap\n", chunksWithHeights);