mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 02:53:51 +00:00
refactor(editor): extract zone-data maintenance into cli_zone_data.cpp
Moves three derived-data maintenance handlers (--fix-zone,
--regen-collision, --build-woc) out of main.cpp into a new
cli_zone_data.{hpp,cpp} module. Distinct from cli_repair
(which fixes manifest-vs-disk drift): these rebuild derived
terrain data and clean up JSON files via load+save:
- fix-zone re-parses + re-saves every JSON sidecar to apply
load-time scrubs and save-time caps
- regen-collision rebuilds WOC for every WHM/WOT in a zone
- build-woc handles single-tile WOC generation
main.cpp shrinks by 104 lines (1,541 to 1,437).
This commit is contained in:
parent
288c4e93b6
commit
fca17592b1
4 changed files with 181 additions and 108 deletions
|
|
@ -1358,6 +1358,7 @@ add_executable(wowee_editor
|
|||
tools/editor/cli_introspect.cpp
|
||||
tools/editor/cli_texture_helpers.cpp
|
||||
tools/editor/cli_mesh_info.cpp
|
||||
tools/editor/cli_zone_data.cpp
|
||||
tools/editor/editor_app.cpp
|
||||
tools/editor/editor_camera.cpp
|
||||
tools/editor/editor_viewport.cpp
|
||||
|
|
|
|||
155
tools/editor/cli_zone_data.cpp
Normal file
155
tools/editor/cli_zone_data.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
#include "cli_zone_data.hpp"
|
||||
|
||||
#include "zone_manifest.hpp"
|
||||
#include "npc_spawner.hpp"
|
||||
#include "object_placer.hpp"
|
||||
#include "quest_editor.hpp"
|
||||
#include "pipeline/wowee_terrain_loader.hpp"
|
||||
#include "pipeline/wowee_collision.hpp"
|
||||
#include "pipeline/adt_loader.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace wowee {
|
||||
namespace editor {
|
||||
namespace cli {
|
||||
|
||||
namespace {
|
||||
|
||||
int handleFixZone(int& i, int argc, char** argv) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
int handleRegenCollision(int& i, int argc, char** argv) {
|
||||
// Find all WHM/WOT pairs under a zone dir and rebuild WOC for each.
|
||||
// Useful after sculpting changes when you want to re-derive
|
||||
// collision in batch instead of one tile at a time.
|
||||
std::string zoneDir = argv[++i];
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(zoneDir)) {
|
||||
std::fprintf(stderr, "regen-collision: %s does not exist\n",
|
||||
zoneDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
int rebuilt = 0, failed = 0;
|
||||
for (auto& entry : fs::recursive_directory_iterator(zoneDir)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
if (entry.path().extension() != ".whm") continue;
|
||||
std::string base = entry.path().string();
|
||||
base = base.substr(0, base.size() - 4); // strip .whm
|
||||
wowee::pipeline::ADTTerrain terrain;
|
||||
if (!wowee::pipeline::WoweeTerrainLoader::load(base, terrain)) {
|
||||
std::fprintf(stderr, " FAILED to load: %s\n", base.c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
auto col = wowee::pipeline::WoweeCollisionBuilder::fromTerrain(terrain);
|
||||
std::string outPath = base + ".woc";
|
||||
if (wowee::pipeline::WoweeCollisionBuilder::save(col, outPath)) {
|
||||
std::printf(" WOC rebuilt: %s (%zu triangles)\n",
|
||||
outPath.c_str(), col.triangles.size());
|
||||
rebuilt++;
|
||||
} else {
|
||||
std::fprintf(stderr, " FAILED to save: %s\n", outPath.c_str());
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
std::printf("regen-collision: %d rebuilt, %d failed\n", rebuilt, failed);
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int handleBuildWoc(int& i, int argc, char** argv) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
bool handleZoneData(int& i, int argc, char** argv, int& outRc) {
|
||||
if (std::strcmp(argv[i], "--fix-zone") == 0 && i + 1 < argc) {
|
||||
outRc = handleFixZone(i, argc, argv); return true;
|
||||
}
|
||||
if (std::strcmp(argv[i], "--regen-collision") == 0 && i + 1 < argc) {
|
||||
outRc = handleRegenCollision(i, argc, argv); return true;
|
||||
}
|
||||
if (std::strcmp(argv[i], "--build-woc") == 0 && i + 1 < argc) {
|
||||
outRc = handleBuildWoc(i, argc, argv); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cli
|
||||
} // namespace editor
|
||||
} // namespace wowee
|
||||
21
tools/editor/cli_zone_data.hpp
Normal file
21
tools/editor/cli_zone_data.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
namespace wowee {
|
||||
namespace editor {
|
||||
namespace cli {
|
||||
|
||||
// Dispatch the zone-data maintenance handlers — re-derive
|
||||
// stored data files (collision, JSON sidecars) from sources
|
||||
// after authoring changes. Distinct from cli_repair (which
|
||||
// fixes manifest-vs-disk drift): these rebuild derived
|
||||
// terrain data and clean up JSON files via load+save.
|
||||
// --fix-zone re-parse + re-save every zone JSON to apply scrubs
|
||||
// --regen-collision rebuild WOC for every WHM/WOT in a zone
|
||||
// --build-woc single-tile WOC build from a WHM/WOT base
|
||||
//
|
||||
// Returns true if matched; outRc holds the exit code.
|
||||
bool handleZoneData(int& i, int argc, char** argv, int& outRc);
|
||||
|
||||
} // namespace cli
|
||||
} // namespace editor
|
||||
} // namespace wowee
|
||||
|
|
@ -59,6 +59,7 @@
|
|||
#include "cli_introspect.hpp"
|
||||
#include "cli_texture_helpers.hpp"
|
||||
#include "cli_mesh_info.hpp"
|
||||
#include "cli_zone_data.hpp"
|
||||
#include "content_pack.hpp"
|
||||
#include "npc_spawner.hpp"
|
||||
#include "object_placer.hpp"
|
||||
|
|
@ -577,6 +578,9 @@ int main(int argc, char* argv[]) {
|
|||
if (wowee::editor::cli::handleMeshInfo(i, argc, argv, outRc)) {
|
||||
return outRc;
|
||||
}
|
||||
if (wowee::editor::cli::handleZoneData(i, argc, argv, outRc)) {
|
||||
return outRc;
|
||||
}
|
||||
}
|
||||
if (std::strcmp(argv[i], "--data") == 0 && i + 1 < argc) {
|
||||
dataPath = argv[++i];
|
||||
|
|
@ -1108,114 +1112,6 @@ 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
|
||||
// collision in batch instead of one tile at a time.
|
||||
std::string zoneDir = argv[++i];
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(zoneDir)) {
|
||||
std::fprintf(stderr, "regen-collision: %s does not exist\n",
|
||||
zoneDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
int rebuilt = 0, failed = 0;
|
||||
for (auto& entry : fs::recursive_directory_iterator(zoneDir)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
if (entry.path().extension() != ".whm") continue;
|
||||
std::string base = entry.path().string();
|
||||
base = base.substr(0, base.size() - 4); // strip .whm
|
||||
wowee::pipeline::ADTTerrain terrain;
|
||||
if (!wowee::pipeline::WoweeTerrainLoader::load(base, terrain)) {
|
||||
std::fprintf(stderr, " FAILED to load: %s\n", base.c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
auto col = wowee::pipeline::WoweeCollisionBuilder::fromTerrain(terrain);
|
||||
std::string outPath = base + ".woc";
|
||||
if (wowee::pipeline::WoweeCollisionBuilder::save(col, outPath)) {
|
||||
std::printf(" WOC rebuilt: %s (%zu triangles)\n",
|
||||
outPath.c_str(), col.triangles.size());
|
||||
rebuilt++;
|
||||
} else {
|
||||
std::fprintf(stderr, " FAILED to save: %s\n", outPath.c_str());
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
std::printf("regen-collision: %d rebuilt, %d failed\n", rebuilt, failed);
|
||||
return failed > 0 ? 1 : 0;
|
||||
} 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], "--export-zone-deps-md") == 0 && i + 1 < argc) {
|
||||
// Markdown counterpart to --list-zone-deps. Writes a sortable
|
||||
// GitHub-rendered table of every external model the zone
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue