diff --git a/tools/editor/editor_app.cpp b/tools/editor/editor_app.cpp index d5161b63..693b5299 100644 --- a/tools/editor/editor_app.cpp +++ b/tools/editor/editor_app.cpp @@ -773,14 +773,19 @@ void EditorApp::loadADT(const std::string& mapName, int tileX, int tileY) { LOG_INFO("ADT loaded: ", mapName, " [", tileX, ",", tileY, "]"); - // Try loading objects/NPCs from output directory if they exist - std::string outBase = "output/" + mapName; - if (objectPlacer_.loadFromFile(outBase + "/objects.json")) - showToast("Loaded " + std::to_string(objectPlacer_.objectCount()) + " objects"); - if (npcSpawner_.loadFromFile(outBase + "/creatures.json")) - showToast("Loaded " + std::to_string(npcSpawner_.spawnCount()) + " NPCs"); - if (questEditor_.loadFromFile(outBase + "/quests.json")) - showToast("Loaded " + std::to_string(questEditor_.questCount()) + " quests"); + // Try loading objects/NPCs/quests from zone directories + for (const char* dir : {"output", "custom_zones"}) { + std::string zoneBase = std::string(dir) + "/" + mapName; + if (objectPlacer_.objectCount() == 0) + if (objectPlacer_.loadFromFile(zoneBase + "/objects.json")) + showToast("Loaded " + std::to_string(objectPlacer_.objectCount()) + " objects"); + if (npcSpawner_.spawnCount() == 0) + if (npcSpawner_.loadFromFile(zoneBase + "/creatures.json")) + showToast("Loaded " + std::to_string(npcSpawner_.spawnCount()) + " NPCs"); + if (questEditor_.questCount() == 0) + if (questEditor_.loadFromFile(zoneBase + "/quests.json")) + showToast("Loaded " + std::to_string(questEditor_.questCount()) + " quests"); + } if (objectPlacer_.objectCount() > 0 || npcSpawner_.spawnCount() > 0) objectsDirty_ = true; } @@ -1254,8 +1259,7 @@ void EditorApp::generateCompleteZone() { void EditorApp::clearAllObjects() { vkDeviceWaitIdle(window_->getVkContext()->getDevice()); objectPlacer_.clearAll(); - npcSpawner_.clearSelection(); - npcSpawner_.getSpawns().clear(); + npcSpawner_.clearAll(); viewport_.clearObjects(); viewport_.updateNpcMarkers({}); terrainEditor_.history().clear(); diff --git a/tools/editor/editor_app.hpp b/tools/editor/editor_app.hpp index 97b38e72..890b5772 100644 --- a/tools/editor/editor_app.hpp +++ b/tools/editor/editor_app.hpp @@ -54,6 +54,7 @@ public: QuestEditor& getQuestEditor() { return questEditor_; } AssetBrowser& getAssetBrowser() { return assetBrowser_; } EditorViewport& getViewport() { return viewport_; } + void setMapName(const std::string& name) { loadedMap_ = name; } rendering::TerrainRenderer* getTerrainRenderer(); rendering::M2Renderer* getM2Renderer() { return viewport_.getM2Renderer(); } pipeline::AssetManager* getAssetManager() { return assetManager_.get(); } diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index f5f378c7..1b1f9206 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -1814,6 +1814,10 @@ void EditorUI::renderQuestPanel(EditorApp& app) { ImGui::SetNextWindowPos(ImVec2(vp->Size.x - 400, 90), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(390, 600), ImGuiCond_FirstUseEver); if (ImGui::Begin("Quest Editor")) { + if (!app.hasTerrainLoaded()) { + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "Load or create terrain first"); + ImGui::End(); return; + } auto& qe = app.getQuestEditor(); auto& tmpl = qe.getTemplate(); @@ -2245,8 +2249,16 @@ void EditorUI::renderPropertiesPanel(EditorApp& app) { if (ImGui::Begin("Info")) { auto* tr = app.getTerrainRenderer(); if (tr && tr->getChunkCount() > 0) { - ImGui::Text("Map: %s [%d, %d]", app.getLoadedMap().c_str(), - app.getLoadedTileX(), app.getLoadedTileY()); + static char renameBuf[128] = {}; + std::strncpy(renameBuf, app.getLoadedMap().c_str(), sizeof(renameBuf) - 1); + ImGui::SetNextItemWidth(140); + if (ImGui::InputText("##mapname", renameBuf, sizeof(renameBuf), + ImGuiInputTextFlags_EnterReturnsTrue)) { + app.setMapName(renameBuf); + app.showToast("Zone renamed: " + std::string(renameBuf)); + } + ImGui::SameLine(); + ImGui::Text("[%d, %d]", app.getLoadedTileX(), app.getLoadedTileY()); ImGui::Text("Chunks: %d Tris: %d", tr->getChunkCount(), tr->getTriangleCount()); ImGui::Text("Objects: %zu NPCs: %zu", app.getObjectPlacer().objectCount(), diff --git a/tools/editor/npc_spawner.hpp b/tools/editor/npc_spawner.hpp index c4b9f134..4cbea703 100644 --- a/tools/editor/npc_spawner.hpp +++ b/tools/editor/npc_spawner.hpp @@ -73,6 +73,7 @@ public: const std::vector& getSpawns() const { return spawns_; } std::vector& getSpawns() { return spawns_; } size_t spawnCount() const { return spawns_.size(); } + void clearAll() { spawns_.clear(); selectedIdx_ = -1; idCounter_ = 1; } // Serialize to/from JSON bool saveToFile(const std::string& path) const; diff --git a/tools/editor/object_placer.hpp b/tools/editor/object_placer.hpp index 72d0dee2..fc2ed7a9 100644 --- a/tools/editor/object_placer.hpp +++ b/tools/editor/object_placer.hpp @@ -62,7 +62,7 @@ public: std::vector& getObjects() { return objects_; } void selectAll(); void selectByType(PlaceableType type); - void clearAll() { objects_.clear(); undoStack_.clear(); selectedIdx_ = -1; selectedIndices_.clear(); } + void clearAll() { objects_.clear(); undoStack_.clear(); selectedIdx_ = -1; selectedIndices_.clear(); uniqueIdCounter_ = 1; } size_t objectCount() const { return objects_.size(); } float getPlacementRotationY() const { return placementRotY_; }