From db47f00657e39aec499e5250fcb81480ec16ed4f Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 14:38:05 -0700 Subject: [PATCH] feat(pipeline): add WOMX (Wowee World Map index) format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Novel open replacement for Blizzard's WDT (top-level world definition table). The 9th open format added to the editor. A WOMX file holds the manifest of which terrain tiles exist within a world plus a tiny bit of map-level metadata. The runtime consults it before attempting to load any individual tile (so missing tiles produce a clean "no data" result instead of a file-not-found error). Format: • magic "WMPX", version 1, little-endian • mapName + worldType (continent/instance/battleground/arena) • gridSize 1..128 (typically 64 for continents) • defaultLightId / defaultWeatherId (atmosphere preset refs, 0 if none — wires into the WOL/WOW pair) • packed bitmap, 1 bit per tile, row-major • A 64x64 manifest is exactly 512 bytes of bitmap API: WoweeWorldMapLoader::save / load / exists; presets makeContinent (64x64 full), makeInstance (4x4 full), makeArena (1x1 full). CLI added (5 flags, 456 total now): --gen-world-map [name] (continent) --gen-world-map-instance [name] (4x4) --gen-world-map-arena [name] (1x1) --info-womx [--json] --validate-womx [--json] Round-trip verified: continent + instance + arena presets all save / load / re-validate to byte-identical state with correct tile counts. --- CMakeLists.txt | 3 + include/pipeline/wowee_world_map.hpp | 82 +++++++++++ src/pipeline/wowee_world_map.cpp | 207 ++++++++++++++++++++++++++ tools/editor/cli_arg_required.cpp | 3 + tools/editor/cli_dispatch.cpp | 2 + tools/editor/cli_help.cpp | 10 ++ tools/editor/cli_world_map.cpp | 209 +++++++++++++++++++++++++++ tools/editor/cli_world_map.hpp | 11 ++ 8 files changed, 527 insertions(+) create mode 100644 include/pipeline/wowee_world_map.hpp create mode 100644 src/pipeline/wowee_world_map.cpp create mode 100644 tools/editor/cli_world_map.cpp create mode 100644 tools/editor/cli_world_map.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 75881d99..51298998 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -596,6 +596,7 @@ set(WOWEE_SOURCES src/pipeline/wowee_collision.cpp src/pipeline/wowee_light.cpp src/pipeline/wowee_weather.cpp + src/pipeline/wowee_world_map.cpp src/pipeline/custom_zone_discovery.cpp src/pipeline/dbc_layout.cpp @@ -1338,6 +1339,7 @@ add_executable(wowee_editor tools/editor/cli_info_density.cpp tools/editor/cli_info_audio.cpp tools/editor/cli_world_info.cpp + tools/editor/cli_world_map.cpp tools/editor/cli_quest_objective.cpp tools/editor/cli_quest_reward.cpp tools/editor/cli_clone.cpp @@ -1412,6 +1414,7 @@ add_executable(wowee_editor src/pipeline/wowee_collision.cpp src/pipeline/wowee_light.cpp src/pipeline/wowee_weather.cpp + src/pipeline/wowee_world_map.cpp src/pipeline/custom_zone_discovery.cpp src/pipeline/terrain_mesh.cpp diff --git a/include/pipeline/wowee_world_map.hpp b/include/pipeline/wowee_world_map.hpp new file mode 100644 index 00000000..08e9a88a --- /dev/null +++ b/include/pipeline/wowee_world_map.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +namespace wowee { +namespace pipeline { + +// Wowee Open World Map index (.womx) — novel replacement for +// Blizzard's WDT (top-level world definition table). A WOMX file +// holds the manifest of which terrain tiles exist within a world, +// plus a tiny bit of map-level metadata. The runtime consults it +// before attempting to load any individual tile (so missing tiles +// produce a clean "no data" instead of a file-not-found error). +// +// The grid is a square of size N×N where N is typically 64 (the +// historical WoW value), but the format permits any N up to 128. +// Tile presence is stored as a packed bitmap (1 bit per tile, +// row-major), so a 64×64 manifest is only 512 bytes. +// +// Binary layout (little-endian): +// magic[4] = "WMPX" +// version (uint32) = current 1 +// nameLen (uint32) + name bytes +// worldType (uint8) = 0=continent, 1=instance, 2=battleground, 3=arena +// gridSize (uint8) = N (1..128) +// pad[2] +// defaultLightId (uint32) -- 0 if no atmosphere preset +// defaultWeatherId (uint32) -- 0 if no atmosphere preset +// reserved[3] (uint32 each) +// bitmapBytes (uint32) = ceil(N*N/8) +// bitmap (bitmapBytes) +struct WoweeWorldMap { + enum WorldType : uint8_t { + Continent = 0, + Instance = 1, + Battleground = 2, + Arena = 3, + }; + + std::string name; + uint8_t worldType = Continent; + uint8_t gridSize = 64; + uint32_t defaultLightId = 0; + uint32_t defaultWeatherId = 0; + + // Packed row-major bitmap: bit (y * gridSize + x) is set + // when a tile exists at column x, row y. + std::vector tileBitmap; + + bool isValid() const { return gridSize > 0 && gridSize <= 128; } + + bool hasTile(uint32_t x, uint32_t y) const; + void setTile(uint32_t x, uint32_t y, bool present); + + // Count of set bits in the bitmap (= number of present tiles). + uint32_t countTiles() const; + + static const char* worldTypeName(uint8_t t); +}; + +class WoweeWorldMapLoader { +public: + static bool save(const WoweeWorldMap& map, + const std::string& basePath); + static WoweeWorldMap load(const std::string& basePath); + static bool exists(const std::string& basePath); + + // Preset emitters used by --gen-world-map* variants. + // + // makeContinent — full 64×64 grid with all tiles present + // (continent-style world map, ~4.3 km²) + // makeInstance — small 4×4 grid for dungeon-scale worlds + // makeArena — 1×1 single-tile arena + static WoweeWorldMap makeContinent(const std::string& mapName); + static WoweeWorldMap makeInstance(const std::string& mapName); + static WoweeWorldMap makeArena(const std::string& mapName); +}; + +} // namespace pipeline +} // namespace wowee diff --git a/src/pipeline/wowee_world_map.cpp b/src/pipeline/wowee_world_map.cpp new file mode 100644 index 00000000..70397575 --- /dev/null +++ b/src/pipeline/wowee_world_map.cpp @@ -0,0 +1,207 @@ +#include "pipeline/wowee_world_map.hpp" + +#include +#include +#include + +namespace wowee { +namespace pipeline { + +namespace { + +constexpr char kMagic[4] = {'W', 'M', 'P', 'X'}; +constexpr uint32_t kVersion = 1; + +template +void writePOD(std::ofstream& os, const T& v) { + os.write(reinterpret_cast(&v), sizeof(T)); +} + +template +bool readPOD(std::ifstream& is, T& v) { + is.read(reinterpret_cast(&v), sizeof(T)); + return is.gcount() == static_cast(sizeof(T)); +} + +std::string normalizePath(std::string base) { + if (base.size() < 5 || base.substr(base.size() - 5) != ".womx") { + base += ".womx"; + } + return base; +} + +size_t bitmapBytesFor(uint32_t gridSize) { + return (static_cast(gridSize) * gridSize + 7) / 8; +} + +} // namespace + +bool WoweeWorldMap::hasTile(uint32_t x, uint32_t y) const { + if (x >= gridSize || y >= gridSize) return false; + size_t bit = static_cast(y) * gridSize + x; + size_t byte = bit / 8; + if (byte >= tileBitmap.size()) return false; + return (tileBitmap[byte] >> (bit & 7)) & 1; +} + +void WoweeWorldMap::setTile(uint32_t x, uint32_t y, bool present) { + if (x >= gridSize || y >= gridSize) return; + size_t bit = static_cast(y) * gridSize + x; + size_t byte = bit / 8; + if (tileBitmap.size() <= byte) tileBitmap.resize(byte + 1, 0); + uint8_t mask = static_cast(1u << (bit & 7)); + if (present) tileBitmap[byte] |= mask; + else tileBitmap[byte] &= static_cast(~mask); +} + +uint32_t WoweeWorldMap::countTiles() const { + uint32_t n = 0; + size_t totalBits = static_cast(gridSize) * gridSize; + for (size_t bit = 0; bit < totalBits; ++bit) { + size_t byte = bit / 8; + if (byte >= tileBitmap.size()) break; + if ((tileBitmap[byte] >> (bit & 7)) & 1) n++; + } + return n; +} + +const char* WoweeWorldMap::worldTypeName(uint8_t t) { + switch (t) { + case Continent: return "continent"; + case Instance: return "instance"; + case Battleground: return "battleground"; + case Arena: return "arena"; + default: return "unknown"; + } +} + +bool WoweeWorldMapLoader::save(const WoweeWorldMap& m, + const std::string& basePath) { + if (m.gridSize == 0 || m.gridSize > 128) return false; + std::ofstream os(normalizePath(basePath), std::ios::binary); + if (!os) return false; + os.write(kMagic, 4); + writePOD(os, kVersion); + uint32_t nameLen = static_cast(m.name.size()); + writePOD(os, nameLen); + if (nameLen > 0) os.write(m.name.data(), nameLen); + writePOD(os, m.worldType); + writePOD(os, m.gridSize); + uint16_t pad = 0; + writePOD(os, pad); + writePOD(os, m.defaultLightId); + writePOD(os, m.defaultWeatherId); + uint32_t reserved = 0; + writePOD(os, reserved); + writePOD(os, reserved); + writePOD(os, reserved); + size_t expectedBytes = bitmapBytesFor(m.gridSize); + uint32_t bitmapBytes = static_cast(expectedBytes); + writePOD(os, bitmapBytes); + // Pad bitmap up to expectedBytes if caller under-sized it + // (setTile may not have grown it to the full grid coverage). + if (m.tileBitmap.size() >= expectedBytes) { + os.write(reinterpret_cast(m.tileBitmap.data()), + expectedBytes); + } else { + if (!m.tileBitmap.empty()) { + os.write(reinterpret_cast(m.tileBitmap.data()), + m.tileBitmap.size()); + } + std::vector tail(expectedBytes - m.tileBitmap.size(), 0); + os.write(reinterpret_cast(tail.data()), tail.size()); + } + return os.good(); +} + +WoweeWorldMap WoweeWorldMapLoader::load(const std::string& basePath) { + WoweeWorldMap out; + std::ifstream is(normalizePath(basePath), std::ios::binary); + if (!is) return out; + char magic[4]; + is.read(magic, 4); + if (std::memcmp(magic, kMagic, 4) != 0) return out; + uint32_t version = 0; + if (!readPOD(is, version) || version != kVersion) return out; + uint32_t nameLen = 0; + if (!readPOD(is, nameLen)) return out; + if (nameLen > 0) { + out.name.resize(nameLen); + is.read(out.name.data(), nameLen); + if (is.gcount() != static_cast(nameLen)) { + out.name.clear(); + return out; + } + } + if (!readPOD(is, out.worldType)) return out; + if (!readPOD(is, out.gridSize)) return out; + uint16_t pad = 0; + if (!readPOD(is, pad)) return out; + if (!readPOD(is, out.defaultLightId)) return out; + if (!readPOD(is, out.defaultWeatherId)) return out; + uint32_t reserved = 0; + if (!readPOD(is, reserved)) return out; + if (!readPOD(is, reserved)) return out; + if (!readPOD(is, reserved)) return out; + uint32_t bitmapBytes = 0; + if (!readPOD(is, bitmapBytes)) return out; + // Cap to a sane upper bound in case the file is corrupted — + // a 128×128 grid is 2048 bytes, so anything > 4 KiB is a sign + // of trouble. + if (bitmapBytes > 4096) { + out.gridSize = 0; + return out; + } + out.tileBitmap.resize(bitmapBytes); + if (bitmapBytes > 0) { + is.read(reinterpret_cast(out.tileBitmap.data()), bitmapBytes); + if (is.gcount() != static_cast(bitmapBytes)) { + out.tileBitmap.clear(); + out.gridSize = 0; + return out; + } + } + return out; +} + +bool WoweeWorldMapLoader::exists(const std::string& basePath) { + std::ifstream is(normalizePath(basePath), std::ios::binary); + return is.good(); +} + +WoweeWorldMap WoweeWorldMapLoader::makeContinent(const std::string& mapName) { + WoweeWorldMap m; + m.name = mapName; + m.worldType = WoweeWorldMap::Continent; + m.gridSize = 64; + m.tileBitmap.assign(bitmapBytesFor(64), 0xFF); + // Last byte may have spare bits past 64*64 — but 64*64 is + // a multiple of 8 (4096), so this is exact and no masking + // is needed. + return m; +} + +WoweeWorldMap WoweeWorldMapLoader::makeInstance(const std::string& mapName) { + WoweeWorldMap m; + m.name = mapName; + m.worldType = WoweeWorldMap::Instance; + m.gridSize = 4; + m.tileBitmap.assign(bitmapBytesFor(4), 0); + for (uint32_t y = 0; y < 4; ++y) + for (uint32_t x = 0; x < 4; ++x) + m.setTile(x, y, true); + return m; +} + +WoweeWorldMap WoweeWorldMapLoader::makeArena(const std::string& mapName) { + WoweeWorldMap m; + m.name = mapName; + m.worldType = WoweeWorldMap::Arena; + m.gridSize = 1; + m.tileBitmap.assign(bitmapBytesFor(1), 0); + m.setTile(0, 0, true); + return m; +} + +} // namespace pipeline +} // namespace wowee diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index c3cefc57..107bd0d9 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -21,6 +21,9 @@ const char* const kArgRequired[] = { "--export-wow-json", "--import-wow-json", "--info-wow", "--validate-wow", "--validate-wom", + "--gen-world-map", "--gen-world-map-instance", + "--gen-world-map-arena", + "--info-womx", "--validate-womx", "--gen-weather-temperate", "--gen-weather-arctic", "--gen-weather-desert", "--gen-weather-stormy", "--gen-zone-atmosphere", diff --git a/tools/editor/cli_dispatch.cpp b/tools/editor/cli_dispatch.cpp index e4956439..a99c3b3d 100644 --- a/tools/editor/cli_dispatch.cpp +++ b/tools/editor/cli_dispatch.cpp @@ -36,6 +36,7 @@ #include "cli_info_density.hpp" #include "cli_info_audio.hpp" #include "cli_world_info.hpp" +#include "cli_world_map.hpp" #include "cli_quest_objective.hpp" #include "cli_quest_reward.hpp" #include "cli_clone.hpp" @@ -113,6 +114,7 @@ constexpr DispatchFn kDispatchTable[] = { handleInfoDensity, handleInfoAudio, handleWorldInfo, + handleWorldMap, handleQuestObjective, handleQuestReward, handleClone, diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index fb22e7ec..0b430c44 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -817,6 +817,16 @@ void printUsage(const char* argv0) { std::printf(" Walk every WOW entry; check typeId / intensity bounds [0,1] / weight > 0 / duration min ≤ max\n"); std::printf(" --validate-wom [--json]\n"); std::printf(" Static sanity checks on .wom: index range, bone refs, bound box, batch coverage, animation track count\n"); + std::printf(" --gen-world-map [mapName]\n"); + std::printf(" Emit .womx world-tile manifest: 64x64 continent grid with all tiles present (open WDT replacement)\n"); + std::printf(" --gen-world-map-instance [mapName]\n"); + std::printf(" Emit .womx world-tile manifest: 4x4 instance grid (small-world / dungeon scale)\n"); + std::printf(" --gen-world-map-arena [mapName]\n"); + std::printf(" Emit .womx world-tile manifest: 1x1 single-tile arena (smallest valid world)\n"); + std::printf(" --info-womx [--json]\n"); + std::printf(" Print WOMX manifest (worldType / gridSize / tilesPresent / defaultLightId / defaultWeatherId)\n"); + std::printf(" --validate-womx [--json]\n"); + std::printf(" Static checks on .womx: gridSize 1..128, worldType in range, tileBitmap matches expected size\n"); std::printf(" --gen-weather-temperate [zoneName]\n"); std::printf(" Emit .wow weather schedule: clear-dominant + occasional rain + fog (forest / grassland)\n"); std::printf(" --gen-weather-arctic [zoneName]\n"); diff --git a/tools/editor/cli_world_map.cpp b/tools/editor/cli_world_map.cpp new file mode 100644 index 00000000..d0fe6c2a --- /dev/null +++ b/tools/editor/cli_world_map.cpp @@ -0,0 +1,209 @@ +#include "cli_world_map.hpp" + +#include "pipeline/wowee_world_map.hpp" +#include + +#include +#include +#include +#include +#include + +namespace wowee { +namespace editor { +namespace cli { + +namespace { + +std::string stripWomxExt(std::string base) { + if (base.size() >= 5 && base.substr(base.size() - 5) == ".womx") + base = base.substr(0, base.size() - 5); + return base; +} + +bool saveOrError(const wowee::pipeline::WoweeWorldMap& m, + const std::string& base, const char* cmd) { + if (!wowee::pipeline::WoweeWorldMapLoader::save(m, base)) { + std::fprintf(stderr, "%s: failed to save %s.womx\n", + cmd, base.c_str()); + return false; + } + return true; +} + +void printGenSummary(const wowee::pipeline::WoweeWorldMap& m, + const std::string& base) { + std::printf("Wrote %s.womx\n", base.c_str()); + std::printf(" name : %s\n", m.name.c_str()); + std::printf(" worldType : %u (%s)\n", m.worldType, + wowee::pipeline::WoweeWorldMap::worldTypeName(m.worldType)); + std::printf(" gridSize : %ux%u tiles\n", m.gridSize, m.gridSize); + std::printf(" tilesPresent: %u / %u\n", + m.countTiles(), + static_cast(m.gridSize) * m.gridSize); +} + +int handleGenContinent(int& i, int argc, char** argv) { + std::string base = argv[++i]; + std::string mapName = "Continent"; + if (i + 1 < argc && argv[i + 1][0] != '-') mapName = argv[++i]; + base = stripWomxExt(base); + auto m = wowee::pipeline::WoweeWorldMapLoader::makeContinent(mapName); + if (!saveOrError(m, base, "gen-world-map")) return 1; + printGenSummary(m, base); + return 0; +} + +int handleGenInstance(int& i, int argc, char** argv) { + std::string base = argv[++i]; + std::string mapName = "Instance"; + if (i + 1 < argc && argv[i + 1][0] != '-') mapName = argv[++i]; + base = stripWomxExt(base); + auto m = wowee::pipeline::WoweeWorldMapLoader::makeInstance(mapName); + if (!saveOrError(m, base, "gen-world-map-instance")) return 1; + printGenSummary(m, base); + return 0; +} + +int handleGenArena(int& i, int argc, char** argv) { + std::string base = argv[++i]; + std::string mapName = "Arena"; + if (i + 1 < argc && argv[i + 1][0] != '-') mapName = argv[++i]; + base = stripWomxExt(base); + auto m = wowee::pipeline::WoweeWorldMapLoader::makeArena(mapName); + if (!saveOrError(m, base, "gen-world-map-arena")) return 1; + printGenSummary(m, base); + return 0; +} + +int handleInfo(int& i, int argc, char** argv) { + std::string base = argv[++i]; + bool jsonOut = (i + 1 < argc && + std::strcmp(argv[i + 1], "--json") == 0); + if (jsonOut) i++; + base = stripWomxExt(base); + if (!wowee::pipeline::WoweeWorldMapLoader::exists(base)) { + std::fprintf(stderr, "WOMX not found: %s.womx\n", base.c_str()); + return 1; + } + auto m = wowee::pipeline::WoweeWorldMapLoader::load(base); + uint32_t total = static_cast(m.gridSize) * m.gridSize; + uint32_t present = m.countTiles(); + if (jsonOut) { + nlohmann::json j; + j["womx"] = base + ".womx"; + j["name"] = m.name; + j["worldType"] = m.worldType; + j["worldTypeName"] = + wowee::pipeline::WoweeWorldMap::worldTypeName(m.worldType); + j["gridSize"] = m.gridSize; + j["totalTiles"] = total; + j["tilesPresent"] = present; + j["defaultLightId"] = m.defaultLightId; + j["defaultWeatherId"] = m.defaultWeatherId; + std::printf("%s\n", j.dump(2).c_str()); + return 0; + } + std::printf("WOMX: %s.womx\n", base.c_str()); + std::printf(" name : %s\n", m.name.c_str()); + std::printf(" worldType : %u (%s)\n", m.worldType, + wowee::pipeline::WoweeWorldMap::worldTypeName(m.worldType)); + std::printf(" gridSize : %ux%u (%u total tiles)\n", + m.gridSize, m.gridSize, total); + std::printf(" tilesPresent : %u (%.1f%%)\n", + present, + total ? (100.0f * present / total) : 0.0f); + std::printf(" defaultLightId : %u\n", m.defaultLightId); + std::printf(" defaultWeatherId : %u\n", m.defaultWeatherId); + return 0; +} + +int handleValidate(int& i, int argc, char** argv) { + std::string base = argv[++i]; + bool jsonOut = (i + 1 < argc && + std::strcmp(argv[i + 1], "--json") == 0); + if (jsonOut) i++; + base = stripWomxExt(base); + if (!wowee::pipeline::WoweeWorldMapLoader::exists(base)) { + std::fprintf(stderr, "validate-womx: WOMX not found: %s.womx\n", + base.c_str()); + return 1; + } + auto m = wowee::pipeline::WoweeWorldMapLoader::load(base); + std::vector errors; + std::vector warnings; + if (m.gridSize == 0 || m.gridSize > 128) { + errors.push_back("gridSize " + std::to_string(m.gridSize) + + " not in range 1..128"); + } + if (m.worldType > wowee::pipeline::WoweeWorldMap::Arena) { + errors.push_back("worldType " + std::to_string(m.worldType) + + " not in known range 0..3"); + } + size_t expectedBytes = + (static_cast(m.gridSize) * m.gridSize + 7) / 8; + if (m.tileBitmap.size() != expectedBytes) { + errors.push_back("tileBitmap size " + + std::to_string(m.tileBitmap.size()) + + " != expected " + std::to_string(expectedBytes) + + " for grid " + std::to_string(m.gridSize) + "x" + + std::to_string(m.gridSize)); + } + if (m.countTiles() == 0) { + warnings.push_back("no tiles present in bitmap (empty world)"); + } + bool ok = errors.empty(); + if (jsonOut) { + nlohmann::json j; + j["womx"] = base + ".womx"; + j["ok"] = ok; + j["errors"] = errors; + j["warnings"] = warnings; + std::printf("%s\n", j.dump(2).c_str()); + return ok ? 0 : 1; + } + std::printf("validate-womx: %s.womx\n", base.c_str()); + if (ok && warnings.empty()) { + std::printf(" OK — %ux%u grid, %u/%u tiles present\n", + m.gridSize, m.gridSize, + m.countTiles(), + static_cast(m.gridSize) * m.gridSize); + return 0; + } + if (!warnings.empty()) { + std::printf(" warnings (%zu):\n", warnings.size()); + for (const auto& w : warnings) + std::printf(" - %s\n", w.c_str()); + } + if (!errors.empty()) { + std::printf(" ERRORS (%zu):\n", errors.size()); + for (const auto& e : errors) + std::printf(" - %s\n", e.c_str()); + } + return ok ? 0 : 1; +} + +} // namespace + +bool handleWorldMap(int& i, int argc, char** argv, int& outRc) { + if (std::strcmp(argv[i], "--gen-world-map") == 0 && i + 1 < argc) { + outRc = handleGenContinent(i, argc, argv); return true; + } + if (std::strcmp(argv[i], "--gen-world-map-instance") == 0 && i + 1 < argc) { + outRc = handleGenInstance(i, argc, argv); return true; + } + if (std::strcmp(argv[i], "--gen-world-map-arena") == 0 && i + 1 < argc) { + outRc = handleGenArena(i, argc, argv); return true; + } + if (std::strcmp(argv[i], "--info-womx") == 0 && i + 1 < argc) { + outRc = handleInfo(i, argc, argv); return true; + } + if (std::strcmp(argv[i], "--validate-womx") == 0 && i + 1 < argc) { + outRc = handleValidate(i, argc, argv); return true; + } + return false; +} + +} // namespace cli +} // namespace editor +} // namespace wowee diff --git a/tools/editor/cli_world_map.hpp b/tools/editor/cli_world_map.hpp new file mode 100644 index 00000000..62636c80 --- /dev/null +++ b/tools/editor/cli_world_map.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace wowee { +namespace editor { +namespace cli { + +bool handleWorldMap(int& i, int argc, char** argv, int& outRc); + +} // namespace cli +} // namespace editor +} // namespace wowee