mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 09:03:52 +00:00
feat: integrate Wowee Open Terrain loader into client terrain pipeline
The wowee client can now load custom zones exported from the editor
using the novel WOT/WHM format — no Blizzard files needed.
Loading priority in TerrainManager::prepareTile():
1. Check custom_zones/{mapName}/{mapName}_{x}_{y}.wot/.whm
2. Check output/{mapName}/{mapName}_{x}_{y}.wot/.whm (editor output)
3. Fall back to World\Maps\...\*.adt (standard extracted data)
Pipeline:
- WoweeTerrainLoader in src/pipeline/ (shared between client + editor)
- Loads .whm binary heightmap (WHM1 magic, 256 chunks × 145 floats)
- Loads .wot JSON metadata (textures, layers, holes, water)
- Populates the same ADTTerrain struct the mesh generator uses
- obj0 merge only runs for ADT-loaded tiles (custom zones have no obj0)
To use: export zone from editor → files appear in output/ → client
loads them automatically on next terrain request for that map name.
This commit is contained in:
parent
94e6d5276e
commit
954894460e
4 changed files with 282 additions and 15 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include "rendering/camera.hpp"
|
||||
#include "audio/ambient_sound_manager.hpp"
|
||||
#include "core/coordinates.hpp"
|
||||
#include "pipeline/wowee_terrain_loader.hpp"
|
||||
#include "core/memory_monitor.hpp"
|
||||
#include "core/profiler.hpp"
|
||||
#include "pipeline/asset_manager.hpp"
|
||||
|
|
@ -310,28 +311,53 @@ std::shared_ptr<PendingTile> TerrainManager::prepareTile(int x, int y) {
|
|||
// Early-exit check — worker should bail fast during shutdown
|
||||
if (!workerRunning.load()) return nullptr;
|
||||
|
||||
// Load ADT file
|
||||
std::string adtPath = getADTPath(coord);
|
||||
auto adtData = assetManager->readFile(adtPath);
|
||||
// Try Wowee Open Terrain format first (custom zones)
|
||||
std::string wotBase = "custom_zones/" + mapName + "/" + mapName + "_" +
|
||||
std::to_string(coord.x) + "_" + std::to_string(coord.y);
|
||||
auto terrainPtr = std::make_unique<pipeline::ADTTerrain>();
|
||||
bool loadedFromWot = false;
|
||||
|
||||
if (adtData.empty()) {
|
||||
logMissingAdtOnce(adtPath);
|
||||
return nullptr;
|
||||
if (pipeline::WoweeTerrainLoader::exists(wotBase)) {
|
||||
if (pipeline::WoweeTerrainLoader::load(wotBase, *terrainPtr)) {
|
||||
loadedFromWot = true;
|
||||
LOG_INFO("Loaded custom zone terrain: ", wotBase);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse ADT — allocate on heap to avoid stack overflow on macOS
|
||||
// (ADTTerrain contains std::array<MapChunk,256> ≈ 280 KB; macOS worker
|
||||
// threads default to 512 KB stack, so two on-stack copies would overflow)
|
||||
auto terrainPtr = std::make_unique<pipeline::ADTTerrain>(pipeline::ADTLoader::load(adtData));
|
||||
if (!terrainPtr->isLoaded()) {
|
||||
LOG_ERROR("Failed to parse ADT terrain: ", adtPath);
|
||||
return nullptr;
|
||||
// Also check output directory (editor exports here)
|
||||
if (!loadedFromWot) {
|
||||
std::string outputBase = "output/" + mapName + "/" + mapName + "_" +
|
||||
std::to_string(coord.x) + "_" + std::to_string(coord.y);
|
||||
if (pipeline::WoweeTerrainLoader::exists(outputBase)) {
|
||||
if (pipeline::WoweeTerrainLoader::load(outputBase, *terrainPtr)) {
|
||||
loadedFromWot = true;
|
||||
LOG_INFO("Loaded editor output terrain: ", outputBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to ADT format
|
||||
if (!loadedFromWot) {
|
||||
std::string adtPath = getADTPath(coord);
|
||||
auto adtData = assetManager->readFile(adtPath);
|
||||
|
||||
if (adtData.empty()) {
|
||||
logMissingAdtOnce(adtPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*terrainPtr = pipeline::ADTLoader::load(adtData);
|
||||
if (!terrainPtr->isLoaded()) {
|
||||
LOG_ERROR("Failed to parse ADT terrain: ", adtPath);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!workerRunning.load()) return nullptr;
|
||||
|
||||
// WotLK split ADTs can store placements in *_obj0.adt.
|
||||
// Merge object chunks so doodads/WMOs (including ground clutter) are available.
|
||||
// Only needed for ADT-loaded tiles, not for WOT custom zones.
|
||||
if (!loadedFromWot) {
|
||||
std::string objPath = "World\\Maps\\" + mapName + "\\" + mapName + "_" +
|
||||
std::to_string(coord.x) + "_" + std::to_string(coord.y) + "_obj0.adt";
|
||||
auto objData = assetManager->readFile(objPath);
|
||||
|
|
@ -386,6 +412,7 @@ std::shared_ptr<PendingTile> TerrainManager::prepareTile(int x, int y) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} // end if (!loadedFromWot) obj0 merge
|
||||
|
||||
// Set tile coordinates so mesh knows where to position this tile in world
|
||||
terrainPtr->coord.x = x;
|
||||
|
|
@ -394,7 +421,7 @@ std::shared_ptr<PendingTile> TerrainManager::prepareTile(int x, int y) {
|
|||
// Generate mesh
|
||||
pipeline::TerrainMesh mesh = pipeline::TerrainMeshGenerator::generate(*terrainPtr);
|
||||
if (mesh.validChunkCount == 0) {
|
||||
LOG_ERROR("Failed to generate terrain mesh: ", adtPath);
|
||||
LOG_ERROR("Failed to generate terrain mesh for tile [", x, ",", y, "]");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue