feat(editor): viewport WOM/WOB lookups also probe per-zone roots

EditorViewport gains setActiveMapName() so rebuildObjects can pass
per-zone prefixes (output/<map>/models|buildings/, custom_zones/<map>/...)
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.
This commit is contained in:
Kelsi 2026-05-06 04:13:03 -07:00
parent db068d480b
commit da2e7a4133
3 changed files with 31 additions and 4 deletions

View file

@ -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;

View file

@ -148,8 +148,14 @@ void EditorViewport::rebuildObjects(const std::vector<PlacedObject>& 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<std::string> 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<PlacedObject>& objects,
bool loaded = false;
// Try WOB open format first (replaces proprietary WMO when available)
if (auto wob = pipeline::WoweeBuildingLoader::tryLoadByGamePath(obj.path);
std::vector<std::string> 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<PlacedObject>& 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<std::string> 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;

View file

@ -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<std::string, uint32_t> 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;