diff --git a/include/core/application.hpp b/include/core/application.hpp index eb6daf4b..38f817b6 100644 --- a/include/core/application.hpp +++ b/include/core/application.hpp @@ -80,6 +80,7 @@ private: void spawnNpcs(); std::string getPlayerModelPath() const; static const char* mapIdToName(uint32_t mapId); + void loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float z); static Application* instance; diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index f5c178d0..2bcd50f1 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -271,6 +271,11 @@ public: using HearthstoneCallback = std::function; void setHearthstoneCallback(HearthstoneCallback cb) { hearthstoneCallback = std::move(cb); } + // World entry callback (online mode - triggered when entering world) + // Parameters: mapId, x, y, z (canonical WoW coordinates) + using WorldEntryCallback = std::function; + void setWorldEntryCallback(WorldEntryCallback cb) { worldEntryCallback_ = std::move(cb); } + // Cooldowns float getSpellCooldown(uint32_t spellId) const; @@ -523,6 +528,7 @@ private: // ---- Phase 3: Spells ---- HearthstoneCallback hearthstoneCallback; + WorldEntryCallback worldEntryCallback_; std::vector knownSpells; std::unordered_map spellCooldowns; // spellId -> remaining seconds uint8_t castCount = 0; diff --git a/src/core/application.cpp b/src/core/application.cpp index 3992e7cd..6c07327c 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -615,6 +615,12 @@ void Application::setupUICallbacks() { } }); + // World entry callback (online mode) - load terrain when entering world + gameHandler->setWorldEntryCallback([this](uint32_t mapId, float x, float y, float z) { + LOG_INFO("Online world entry: mapId=", mapId, " pos=(", x, ", ", y, ", ", z, ")"); + loadOnlineWorldTerrain(mapId, x, y, z); + }); + // "Create Character" button on character screen uiManager->getCharacterScreen().setOnCreateCharacter([this]() { uiManager->getCharacterCreateScreen().reset(); @@ -1507,5 +1513,59 @@ void Application::teleportTo(int presetIndex) { LOG_INFO("Teleport to ", preset.label, " complete"); } +void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float z) { + if (!renderer || !assetManager || !assetManager->isInitialized()) { + LOG_WARNING("Cannot load online terrain: renderer or assets not ready"); + return; + } + + std::string mapName = mapIdToName(mapId); + LOG_INFO("Loading online world terrain for map '", mapName, "' (ID ", mapId, ")"); + + // Convert server coordinates to canonical WoW coordinates + // Server sends: X=West (canonical.Y), Y=North (canonical.X), Z=Up + glm::vec3 spawnCanonical = core::coords::serverToCanonical(glm::vec3(x, y, z)); + glm::vec3 spawnRender = core::coords::canonicalToRender(spawnCanonical); + + // Set camera position + if (renderer->getCameraController()) { + renderer->getCameraController()->setDefaultSpawn(spawnRender, 0.0f, 15.0f); + renderer->getCameraController()->reset(); + } + + // Set map name for WMO renderer + if (renderer->getWMORenderer()) { + renderer->getWMORenderer()->setMapName(mapName); + } + + // Set map name for terrain manager + if (renderer->getTerrainManager()) { + renderer->getTerrainManager()->setMapName(mapName); + } + + // Compute ADT tile from canonical coordinates + auto [tileX, tileY] = core::coords::canonicalToTile(spawnCanonical.x, spawnCanonical.y); + std::string adtPath = "World\\Maps\\" + mapName + "\\" + mapName + "_" + + std::to_string(tileX) + "_" + std::to_string(tileY) + ".adt"; + LOG_INFO("Loading ADT tile [", tileX, ",", tileY, "] from canonical (", + spawnCanonical.x, ", ", spawnCanonical.y, ", ", spawnCanonical.z, ")"); + + // Load the initial terrain tile + bool terrainOk = renderer->loadTestTerrain(assetManager.get(), adtPath); + if (!terrainOk) { + LOG_WARNING("Could not load terrain for online world - atmospheric rendering only"); + } else { + LOG_INFO("Online world terrain loading initiated"); + + // Trigger terrain streaming for surrounding tiles + if (renderer->getTerrainManager() && renderer->getCamera()) { + renderer->getTerrainManager()->update(*renderer->getCamera(), 1.0f); + } + } + + // Set game state + setState(AppState::IN_GAME); +} + } // namespace core } // namespace wowee diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index e645e47c..df43d74a 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -2102,6 +2102,11 @@ void GameHandler::handleLoginVerifyWorld(network::Packet& packet) { socket->send(activeMoverPacket); LOG_INFO("Sent CMSG_SET_ACTIVE_MOVER for player 0x", std::hex, playerGuid, std::dec); } + + // Notify application to load terrain for this map/position (online mode) + if (worldEntryCallback_) { + worldEntryCallback_(data.mapId, data.x, data.y, data.z); + } } void GameHandler::handleAccountDataTimes(network::Packet& packet) { diff --git a/src/rendering/terrain_manager.cpp b/src/rendering/terrain_manager.cpp index 8895b134..8f569407 100644 --- a/src/rendering/terrain_manager.cpp +++ b/src/rendering/terrain_manager.cpp @@ -800,7 +800,6 @@ void TerrainManager::getTileBounds(const TileCoord& coord, float& minX, float& m std::string TerrainManager::getADTPath(const TileCoord& coord) const { // Format: World\Maps\{MapName}\{MapName}_{X}_{Y}.adt - // Example: Azeroth_32_49.adt for tile at coord.x=32, coord.y=49 return "World\\Maps\\" + mapName + "\\" + mapName + "_" + std::to_string(coord.x) + "_" + std::to_string(coord.y) + ".adt"; }