From da2e7a4133f119c16a42b150091614e6d4419f4f Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 04:13:03 -0700 Subject: [PATCH] feat(editor): viewport WOM/WOB lookups also probe per-zone roots EditorViewport gains setActiveMapName() so rebuildObjects can pass per-zone prefixes (output//models|buildings/, custom_zones//...) to tryLoadByGamePath. EditorApp wires it from loadADT, loadWMOInstance, and createNewTerrain. Now the editor's preview mirrors the main game's priority: per-zone WOM/WOB beats global custom_zones/, beats game data. --- tools/editor/editor_app.cpp | 3 +++ tools/editor/editor_viewport.cpp | 25 +++++++++++++++++++++---- tools/editor/editor_viewport.hpp | 7 +++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/tools/editor/editor_app.cpp b/tools/editor/editor_app.cpp index 11f431ab..1643fe72 100644 --- a/tools/editor/editor_app.cpp +++ b/tools/editor/editor_app.cpp @@ -842,6 +842,7 @@ bool EditorApp::loadWMOInstance(const std::string& mapName) { loadedMap_ = mapName; loadedTileX_ = 32; loadedTileY_ = 32; + viewport_.setActiveMapName(mapName); // Position camera near the WMO camera_.setPosition(wmoPos + glm::vec3(0, 0, 50)); @@ -938,6 +939,7 @@ void EditorApp::loadADT(const std::string& mapName, int tileX, int tileY) { loadedMap_ = mapName; loadedTileX_ = tileX; loadedTileY_ = tileY; + viewport_.setActiveMapName(mapName); // Track recent zones (deduplicate, max 8) recentZones_.erase(std::remove_if(recentZones_.begin(), recentZones_.end(), @@ -1046,6 +1048,7 @@ void EditorApp::createNewTerrain(const std::string& mapName, int tileX, int tile loadedMap_ = mapName; loadedTileX_ = tileX; loadedTileY_ = tileY; + viewport_.setActiveMapName(mapName); lastObjCount_ = 0; lastNpcCount_ = 0; objectsDirty_ = false; diff --git a/tools/editor/editor_viewport.cpp b/tools/editor/editor_viewport.cpp index 2231f64f..931b4c4c 100644 --- a/tools/editor/editor_viewport.cpp +++ b/tools/editor/editor_viewport.cpp @@ -148,8 +148,14 @@ void EditorViewport::rebuildObjects(const std::vector& objects, pipeline::M2Model model; bool loaded = false; - // Try WOM open format first (replaces proprietary M2 when available) - if (auto wom = pipeline::WoweeModelLoader::tryLoadByGamePath(obj.path); + // Try WOM open format first (replaces proprietary M2 when available). + // Per-zone WOM directories shadow the global custom_zones folder. + std::vector womExtra; + if (!activeMapName_.empty()) { + womExtra.push_back("output/" + activeMapName_ + "/models/"); + womExtra.push_back("custom_zones/" + activeMapName_ + "/models/"); + } + if (auto wom = pipeline::WoweeModelLoader::tryLoadByGamePath(obj.path, womExtra); wom.isValid()) { model = pipeline::WoweeModelLoader::toM2(wom); loaded = true; @@ -210,7 +216,12 @@ void EditorViewport::rebuildObjects(const std::vector& objects, bool loaded = false; // Try WOB open format first (replaces proprietary WMO when available) - if (auto wob = pipeline::WoweeBuildingLoader::tryLoadByGamePath(obj.path); + std::vector wobExtra; + if (!activeMapName_.empty()) { + wobExtra.push_back("output/" + activeMapName_ + "/buildings/"); + wobExtra.push_back("custom_zones/" + activeMapName_ + "/buildings/"); + } + if (auto wob = pipeline::WoweeBuildingLoader::tryLoadByGamePath(obj.path, wobExtra); wob.isValid() && pipeline::WoweeBuildingLoader::toWMOModel(wob, model)) { loaded = true; @@ -274,7 +285,13 @@ void EditorViewport::rebuildObjects(const std::vector& objects, // Try WOM open format first (replaces proprietary M2 when available) pipeline::M2Model model; bool loaded = false; - if (auto wom = pipeline::WoweeModelLoader::tryLoadByGamePath(npc.modelPath); + std::vector npcWomExtra; + if (!activeMapName_.empty()) { + npcWomExtra.push_back("output/" + activeMapName_ + "/models/"); + npcWomExtra.push_back("custom_zones/" + activeMapName_ + "/models/"); + } + if (auto wom = pipeline::WoweeModelLoader::tryLoadByGamePath( + npc.modelPath, npcWomExtra); wom.isValid()) { model = pipeline::WoweeModelLoader::toM2(wom); loaded = true; diff --git a/tools/editor/editor_viewport.hpp b/tools/editor/editor_viewport.hpp index 307dab18..7927afa2 100644 --- a/tools/editor/editor_viewport.hpp +++ b/tools/editor/editor_viewport.hpp @@ -80,6 +80,9 @@ public: rendering::TerrainRenderer* getTerrainRenderer() { return terrainRenderer_.get(); } rendering::M2Renderer* getM2Renderer() { return m2Renderer_.get(); } + /** Set the active map name so WOM/WOB lookups can probe per-zone roots first. */ + void setActiveMapName(const std::string& name) { activeMapName_ = name; } + private: bool createPerFrameResources(); void destroyPerFrameResources(); @@ -122,6 +125,10 @@ private: std::unordered_map persistentWMOModelIds_; uint32_t nextPersistentModelId_ = 1; + // Active map name used to build per-zone WOM/WOB prefixes so per-zone + // overrides win over global custom_zones/ assets. + std::string activeMapName_; + // Ghost preview state std::string ghostModelPath_; uint32_t ghostModelId_ = 0;