diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index 3e3dba7f..8953a78f 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -71,6 +71,12 @@ public: */ bool loadTestTerrain(pipeline::AssetManager* assetManager, const std::string& adtPath); + /** + * Initialize all sub-renderers (WMO, M2, Character, terrain, water, minimap, etc.) + * without loading any ADT tile. Used by WMO-only maps (dungeons/raids/BGs). + */ + bool initializeRenderers(pipeline::AssetManager* assetManager, const std::string& mapName); + /** * Enable/disable terrain rendering */ diff --git a/src/core/application.cpp b/src/core/application.cpp index c2e85c44..d84ee47b 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -3430,19 +3430,14 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float // Initialize renderers if they don't exist yet (first login to a WMO-only map). // On map change, renderers already exist from the previous map. if (!renderer->getWMORenderer() || !renderer->getTerrainManager()) { - auto [tileX, tileY] = core::coords::canonicalToTile(spawnCanonical.x, spawnCanonical.y); - std::string dummyAdtPath = "World\\Maps\\" + mapName + "\\" + mapName + "_" + - std::to_string(tileX) + "_" + std::to_string(tileY) + ".adt"; - LOG_WARNING("WMO-only: calling loadTestTerrain to create renderers"); - renderer->loadTestTerrain(assetManager.get(), dummyAdtPath); + renderer->initializeRenderers(assetManager.get(), mapName); } - // Set map name on WMO and terrain renderers + // Set map name on WMO renderer and disable terrain streaming (no ADT tiles for instances) if (renderer->getWMORenderer()) { renderer->getWMORenderer()->setMapName(mapName); } if (renderer->getTerrainManager()) { - renderer->getTerrainManager()->setMapName(mapName); renderer->getTerrainManager()->setStreamingEnabled(false); } @@ -3635,14 +3630,10 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float LOG_INFO("Online world terrain loading initiated"); } - // Set map name on the newly-created WMO/terrain renderers - // (loadTestTerrain creates them, so the earlier setMapName at line ~3296 was a no-op) + // Set map name on WMO renderer (initializeRenderers handles terrain/minimap/worldMap) if (renderer->getWMORenderer()) { renderer->getWMORenderer()->setMapName(mapName); } - if (renderer->getTerrainManager()) { - renderer->getTerrainManager()->setMapName(mapName); - } // Character renderer is created inside loadTestTerrain(), so spawn the // player model now that the renderer actually exists. @@ -3873,9 +3864,6 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float // Track which map we actually loaded (used by same-map teleport check). loadedMapId_ = mapId; - // Set game state - setState(AppState::IN_GAME); - // Clear loading flag and process any deferred world entry. // A deferred entry occurs when SMSG_NEW_WORLD arrived during our warmup // (e.g., an area trigger in a dungeon immediately teleporting the player out). @@ -3887,9 +3875,13 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float worldEntryMovementGraceTimer_ = 2.0f; taxiLandingClampTimer_ = 0.0f; lastTaxiFlight_ = false; - // Recursive call — sets loadedMapId_ to entry.mapId inside. + // Recursive call — sets loadedMapId_ and IN_GAME state for the final map. loadOnlineWorldTerrain(entry.mapId, entry.x, entry.y, entry.z); + return; // The recursive call handles setState(IN_GAME). } + + // Only enter IN_GAME when this is the final map (no deferred entry pending). + setState(AppState::IN_GAME); } void Application::buildCreatureDisplayLookups() { diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 4f3a77ae..34d2dcb4 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -8795,33 +8795,6 @@ void GameHandler::checkAreaTriggers() { const float py = movementInfo.y; const float pz = movementInfo.z; - // Debug: log player position periodically to verify trigger proximity - static int debugCounter = 0; - if (++debugCounter >= 4) { // every ~1s at 0.25s interval - debugCounter = 0; - int mapTriggerCount = 0; - float closestDist = 999999.0f; - uint32_t closestId = 0; - float closestR = 0, closestBoxL = 0, closestBoxW = 0, closestBoxH = 0; - bool closestActive = false; - for (const auto& at : areaTriggers_) { - if (at.mapId != currentMapId_) continue; - mapTriggerCount++; - float dx = px - at.x, dy = py - at.y, dz = pz - at.z; - float dist = std::sqrt(dx*dx + dy*dy + dz*dz); - if (dist < closestDist) { - closestDist = dist; closestId = at.id; - closestR = at.radius; closestBoxL = at.boxLength; closestBoxW = at.boxWidth; closestBoxH = at.boxHeight; - closestActive = activeAreaTriggers_.count(at.id) > 0; - } - } - LOG_WARNING("AreaTrigger check: player=(", px, ", ", py, ", ", pz, - ") map=", currentMapId_, " closest=AT", closestId, - " dist=", closestDist, " r=", closestR, - " box=(", closestBoxL, ",", closestBoxW, ",", closestBoxH, - ") active=", closestActive); - } - // On first check after map transfer, just mark which triggers we're inside // without firing them — prevents exit portal from immediately sending us back bool suppressFirst = areaTriggerSuppressFirst_; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 85ce1788..1bce7855 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -3344,13 +3344,13 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) { // initPostProcess(), resizePostProcess(), shutdownPostProcess() removed — // post-process pipeline is now handled by Vulkan (Phase 6 cleanup). -bool Renderer::loadTestTerrain(pipeline::AssetManager* assetManager, const std::string& adtPath) { +bool Renderer::initializeRenderers(pipeline::AssetManager* assetManager, const std::string& mapName) { if (!assetManager) { LOG_ERROR("Asset manager is null"); return false; } - LOG_INFO("Loading test terrain: ", adtPath); + LOG_INFO("Initializing renderers for map: ", mapName); // Create terrain renderer if not already created if (!terrainRenderer) { @@ -3466,49 +3466,12 @@ bool Renderer::loadTestTerrain(pipeline::AssetManager* assetManager, const std:: } } - // Parse tile coordinates from ADT path - // Format: World\Maps\{MapName}\{MapName}_{X}_{Y}.adt - int tileX = 32, tileY = 49; // defaults - { - // Find last path separator - size_t lastSep = adtPath.find_last_of("\\/"); - if (lastSep != std::string::npos) { - std::string filename = adtPath.substr(lastSep + 1); - // Find first underscore after map name - size_t firstUnderscore = filename.find('_'); - if (firstUnderscore != std::string::npos) { - size_t secondUnderscore = filename.find('_', firstUnderscore + 1); - if (secondUnderscore != std::string::npos) { - size_t dot = filename.find('.', secondUnderscore); - if (dot != std::string::npos) { - tileX = std::stoi(filename.substr(firstUnderscore + 1, secondUnderscore - firstUnderscore - 1)); - tileY = std::stoi(filename.substr(secondUnderscore + 1, dot - secondUnderscore - 1)); - } - } - } - // Extract map name - std::string mapName = filename.substr(0, firstUnderscore != std::string::npos ? firstUnderscore : filename.size()); - terrainManager->setMapName(mapName); - if (minimap) { - minimap->setMapName(mapName); - } - if (worldMap) { - worldMap->setMapName(mapName); - } - } - } + // Set map name on sub-renderers + if (terrainManager) terrainManager->setMapName(mapName); + if (minimap) minimap->setMapName(mapName); + if (worldMap) worldMap->setMapName(mapName); - LOG_INFO("Enqueuing initial tile [", tileX, ",", tileY, "] via terrain manager"); - - // Enqueue the initial tile for async loading (avoids long sync stalls) - if (!terrainManager->enqueueTile(tileX, tileY)) { - LOG_ERROR("Failed to enqueue initial tile [", tileX, ",", tileY, "]"); - return false; - } - - terrainLoaded = true; - - // Initialize music manager with asset manager + // Initialize audio managers if (musicManager && assetManager && !cachedAssetManager) { audio::AudioEngine::instance().setAssetManager(assetManager); musicManager->initialize(assetManager); @@ -3569,11 +3532,69 @@ bool Renderer::loadTestTerrain(pipeline::AssetManager* assetManager, const std:: cachedAssetManager = assetManager; } - // Snap camera to ground now that terrain is loaded + // Snap camera to ground if (cameraController) { cameraController->reset(); } + return true; +} + +bool Renderer::loadTestTerrain(pipeline::AssetManager* assetManager, const std::string& adtPath) { + if (!assetManager) { + LOG_ERROR("Asset manager is null"); + return false; + } + + LOG_INFO("Loading test terrain: ", adtPath); + + // Extract map name from ADT path for renderer initialization + std::string mapName; + { + size_t lastSep = adtPath.find_last_of("\\/"); + if (lastSep != std::string::npos) { + std::string filename = adtPath.substr(lastSep + 1); + size_t firstUnderscore = filename.find('_'); + mapName = filename.substr(0, firstUnderscore != std::string::npos ? firstUnderscore : filename.size()); + } + } + + // Initialize all sub-renderers + if (!initializeRenderers(assetManager, mapName)) { + return false; + } + + // Parse tile coordinates from ADT path + // Format: World\Maps\{MapName}\{MapName}_{X}_{Y}.adt + int tileX = 32, tileY = 49; // defaults + { + size_t lastSep = adtPath.find_last_of("\\/"); + if (lastSep != std::string::npos) { + std::string filename = adtPath.substr(lastSep + 1); + size_t firstUnderscore = filename.find('_'); + if (firstUnderscore != std::string::npos) { + size_t secondUnderscore = filename.find('_', firstUnderscore + 1); + if (secondUnderscore != std::string::npos) { + size_t dot = filename.find('.', secondUnderscore); + if (dot != std::string::npos) { + tileX = std::stoi(filename.substr(firstUnderscore + 1, secondUnderscore - firstUnderscore - 1)); + tileY = std::stoi(filename.substr(secondUnderscore + 1, dot - secondUnderscore - 1)); + } + } + } + } + } + + LOG_INFO("Enqueuing initial tile [", tileX, ",", tileY, "] via terrain manager"); + + // Enqueue the initial tile for async loading (avoids long sync stalls) + if (!terrainManager->enqueueTile(tileX, tileY)) { + LOG_ERROR("Failed to enqueue initial tile [", tileX, ",", tileY, "]"); + return false; + } + + terrainLoaded = true; + LOG_INFO("Test terrain loaded successfully!"); LOG_INFO(" Chunks: ", terrainRenderer->getChunkCount()); LOG_INFO(" Triangles: ", terrainRenderer->getTriangleCount());