feat(extract): emit WHM+WOT+WOC for ADT terrain tiles

Final piece of the open-format emit pipeline:
  --emit-terrain  foo.adt → foo.whm + foo.wot + foo.woc

With this, --emit-open now produces a fully open-format zone
alongside every Blizzard MPQ extraction:
  BLP  → PNG       (textures)
  DBC  → JSON      (data tables)
  M2   → WOM       (models, with skin merge)
  WMO  → WOB       (buildings, with group merge)
  ADT  → WHM/WOT   (terrain heights + metadata)
       → WOC       (collision mesh derived from heights)

Originals stay on disk and indexed by manifest.json so private
servers continue to load proprietary formats; wowee runtime/editor
read the open formats directly. One extraction now feeds both
audiences with no separate conversion pass.

Implementation:
- Inline WHM+WOT writer in open_format_emitter.cpp (mirrors the
  editor's WoweeTerrain::exportOpen but without the PNG-preview /
  normal-map deps so the extractor stays editor-independent).
- Tile coords (x,y) parsed from <map>_<x>_<y>.adt filename.
- Collision mesh derived via WoweeCollisionBuilder::fromTerrain
  (terrain triangles only — WMO collision overlays would need
  asset manager and aren't worth the extractor complexity).
This commit is contained in:
Kelsi 2026-05-06 10:36:14 -07:00
parent e6ace7cce5
commit d4c69a2b46
6 changed files with 182 additions and 4 deletions

View file

@ -28,7 +28,8 @@ static void printUsage(const char* prog) {
<< " --emit-json-dbc Emit foo.json next to every extracted foo.dbc\n"
<< " --emit-wom Emit foo.wom next to every extracted foo.m2 (+skin)\n"
<< " --emit-wob Emit foo.wob next to every extracted foo.wmo (+groups)\n"
<< " --emit-open Shortcut: enable every open-format emitter (png+json+wom+wob)\n"
<< " --emit-terrain Emit foo.whm + foo.wot + foo.woc next to every foo.adt\n"
<< " --emit-open Shortcut: enable every open-format emitter (png+json+wom+wob+terrain)\n"
<< " --verify CRC32 verify all extracted files\n"
<< " --threads <N> Number of extraction threads (default: auto)\n"
<< " --verbose Verbose output\n"
@ -65,12 +66,15 @@ int main(int argc, char** argv) {
opts.emitWom = true;
} else if (std::strcmp(argv[i], "--emit-wob") == 0) {
opts.emitWob = true;
} else if (std::strcmp(argv[i], "--emit-terrain") == 0) {
opts.emitTerrain = true;
} else if (std::strcmp(argv[i], "--emit-open") == 0) {
// Meta-flag: turn on every available open-format emitter.
opts.emitPng = true;
opts.emitJsonDbc = true;
opts.emitWom = true;
opts.emitWob = true;
opts.emitTerrain = true;
} else if (std::strcmp(argv[i], "--dbc-csv-out") == 0 && i + 1 < argc) {
opts.dbcCsvOutputDir = argv[++i];
} else if (std::strcmp(argv[i], "--listfile") == 0 && i + 1 < argc) {