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

@ -20,6 +20,8 @@ struct OpenFormatStats {
uint32_t jsonDbcOk = 0, jsonDbcFail = 0;
uint32_t womOk = 0, womFail = 0;
uint32_t wobOk = 0, wobFail = 0;
uint32_t whmOk = 0, whmFail = 0;
uint32_t wocOk = 0, wocFail = 0;
};
// Convert one BLP file on disk to a PNG side-file.
@ -40,11 +42,18 @@ bool emitWomFromM2(const std::string& m2Path, const std::string& womBase);
// matching <base>_NNN.wmo group files if present.
bool emitWobFromWmo(const std::string& wmoPath, const std::string& wobBase);
// Convert one ADT file on disk to a WHM (binary heightmap) + WOT (JSON
// metadata) pair, plus a WOC (collision mesh) for movement queries.
// Returns true if all three were written. tileX/tileY are parsed from
// the filename (e.g. "MapName_32_48.adt").
bool emitTerrainFromAdt(const std::string& adtPath, const std::string& outBase);
// Walk an extracted-asset directory and emit open-format side-files for
// every requested format. Counts accumulated into stats.
void emitOpenFormats(const std::string& rootDir,
bool emitPng, bool emitJsonDbc,
bool emitWom, bool emitWob,
bool emitTerrain,
OpenFormatStats& stats);
} // namespace tools