From db068d480be07e553ffd0fa3d9db9764617b1687 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 04:10:12 -0700 Subject: [PATCH] feat(wob): tryLoadByGamePath helper, used by editor + terrain_manager Mirrors the WOM tryLoadByGamePath API: probes custom_zones/buildings/ + output/buildings/ by default, with optional extraPrefixes (e.g. per-zone output//buildings/) checked first. Both the editor and the main game's terrain_manager now use the helper, removing duplicate inline lookup loops in two more places. --- include/pipeline/wowee_building.hpp | 9 +++++++++ src/pipeline/wowee_building.cpp | 24 ++++++++++++++++++++++++ src/rendering/terrain_manager.cpp | 27 +++++++++++---------------- tools/editor/editor_viewport.cpp | 19 ++++--------------- 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/include/pipeline/wowee_building.hpp b/include/pipeline/wowee_building.hpp index 0c611608..51565f3f 100644 --- a/include/pipeline/wowee_building.hpp +++ b/include/pipeline/wowee_building.hpp @@ -67,6 +67,15 @@ public: // Convert WMOModel to WOB (for editor export) static WoweeBuilding fromWMO(const class WMOModel& wmo, const std::string& name = ""); + + // Convenience: try loading .wob from the standard editor + // search paths (custom_zones/buildings/, output/buildings/). `extraPrefixes` + // are tried before the defaults — pass per-zone roots like + // {"output//buildings/", "custom_zones//buildings/"} when the + // caller knows the active zone. Returns valid building on hit. + static WoweeBuilding tryLoadByGamePath( + const std::string& gamePath, + const std::vector& extraPrefixes = {}); }; } // namespace pipeline diff --git a/src/pipeline/wowee_building.cpp b/src/pipeline/wowee_building.cpp index 978786c6..ee002b9d 100644 --- a/src/pipeline/wowee_building.cpp +++ b/src/pipeline/wowee_building.cpp @@ -431,5 +431,29 @@ WoweeBuilding WoweeBuildingLoader::fromWMO(const WMOModel& wmo, const std::strin return bld; } +WoweeBuilding WoweeBuildingLoader::tryLoadByGamePath( + const std::string& gamePath, + const std::vector& extraPrefixes) { + std::string base = gamePath; + auto dot = base.rfind('.'); + if (dot != std::string::npos) base = base.substr(0, dot); + std::replace(base.begin(), base.end(), '\\', '/'); + auto tryPrefix = [&](const std::string& prefix) -> WoweeBuilding { + std::string full = prefix + base; + if (exists(full)) { + auto wob = load(full); + if (wob.isValid()) return wob; + } + return {}; + }; + for (const auto& p : extraPrefixes) { + if (auto w = tryPrefix(p); w.isValid()) return w; + } + for (const char* p : {"custom_zones/buildings/", "output/buildings/"}) { + if (auto w = tryPrefix(p); w.isValid()) return w; + } + return {}; +} + } // namespace pipeline } // namespace wowee diff --git a/src/rendering/terrain_manager.cpp b/src/rendering/terrain_manager.cpp index 37e84bda..84521603 100644 --- a/src/rendering/terrain_manager.cpp +++ b/src/rendering/terrain_manager.cpp @@ -614,22 +614,17 @@ std::shared_ptr TerrainManager::prepareTile(int x, int y) { bool wobLoaded = false; pipeline::WMOModel wmoModel; { - std::string wobBase = wmoPath; - auto wobDot = wobBase.rfind('.'); - if (wobDot != std::string::npos) wobBase = wobBase.substr(0, wobDot); - std::replace(wobBase.begin(), wobBase.end(), '\\', '/'); - std::vector wobPrefixes = {"custom_zones/buildings/", "output/" + mapName + "/buildings/"}; - for (const auto& prefix : wobPrefixes) { - if (pipeline::WoweeBuildingLoader::exists(prefix + wobBase)) { - auto wob = pipeline::WoweeBuildingLoader::load(prefix + wobBase); - if (wob.isValid()) { - if (pipeline::WoweeBuildingLoader::toWMOModel(wob, wmoModel)) { - LOG_INFO("Loaded WOB building: ", prefix + wobBase); - wobLoaded = true; - } - } - break; - } + // Per-zone overrides win over global custom_zones/ overrides. + std::vector extraPrefixes = { + "output/" + mapName + "/buildings/", + "custom_zones/" + mapName + "/buildings/", + }; + auto wob = pipeline::WoweeBuildingLoader::tryLoadByGamePath( + wmoPath, extraPrefixes); + if (wob.isValid() && + pipeline::WoweeBuildingLoader::toWMOModel(wob, wmoModel)) { + LOG_INFO("Loaded WOB building: ", wmoPath); + wobLoaded = true; } } diff --git a/tools/editor/editor_viewport.cpp b/tools/editor/editor_viewport.cpp index 3b1d9961..2231f64f 100644 --- a/tools/editor/editor_viewport.cpp +++ b/tools/editor/editor_viewport.cpp @@ -210,21 +210,10 @@ void EditorViewport::rebuildObjects(const std::vector& objects, bool loaded = false; // Try WOB open format first (replaces proprietary WMO when available) - { - std::string wobBase = obj.path; - auto wobDot = wobBase.rfind('.'); - if (wobDot != std::string::npos) wobBase = wobBase.substr(0, wobDot); - std::replace(wobBase.begin(), wobBase.end(), '\\', '/'); - for (const char* prefix : {"custom_zones/buildings/", "output/buildings/"}) { - if (pipeline::WoweeBuildingLoader::exists(std::string(prefix) + wobBase)) { - auto wob = pipeline::WoweeBuildingLoader::load(std::string(prefix) + wobBase); - if (wob.isValid() && - pipeline::WoweeBuildingLoader::toWMOModel(wob, model)) { - loaded = true; - break; - } - } - } + if (auto wob = pipeline::WoweeBuildingLoader::tryLoadByGamePath(obj.path); + wob.isValid() && + pipeline::WoweeBuildingLoader::toWMOModel(wob, model)) { + loaded = true; } if (!loaded) {