From 5684b16721cf114134464b14095437377b952dd5 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Thu, 12 Mar 2026 20:52:58 -0700 Subject: [PATCH] fix: talent screen hang (uint8_t overflow) and camera pitch limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change maxRow/maxCol from uint8_t to int in renderTalentTree to prevent infinite loop: uint8_t col <= 255 never exits since col wraps 255→0. Add sanity cap of 15 rows/cols to guard against corrupt DBC data. - Fix dangling reference warning in getFormattedTitle (lambda reference) - Raise MAX_PITCH from 35° to 88° to match WoW standard upward look range --- include/rendering/camera_controller.hpp | 2 +- src/game/game_handler.cpp | 8 +++----- src/ui/talent_screen.cpp | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/rendering/camera_controller.hpp b/include/rendering/camera_controller.hpp index fbddd523..235e171f 100644 --- a/include/rendering/camera_controller.hpp +++ b/include/rendering/camera_controller.hpp @@ -186,7 +186,7 @@ private: static constexpr float COLLISION_FOCUS_RADIUS_THIRD_PERSON = 20.0f; // Reduced for performance static constexpr float COLLISION_FOCUS_RADIUS_FREE_FLY = 20.0f; static constexpr float MIN_PITCH = -88.0f; // Look almost straight down - static constexpr float MAX_PITCH = 35.0f; // Limited upward look + static constexpr float MAX_PITCH = 88.0f; // Look almost straight up (WoW standard) glm::vec3* followTarget = nullptr; glm::vec3 smoothedCamPos = glm::vec3(0.0f); // For smooth camera movement float smoothedCollisionDist_ = -1.0f; // Asymmetrically-smoothed WMO collision limit (-1 = uninitialised) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 52aa12f9..c11f3607 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -20752,11 +20752,9 @@ std::string GameHandler::getFormattedTitle(uint32_t bit) const { auto it = titleNameCache_.find(bit); if (it == titleNameCache_.end() || it->second.empty()) return {}; - const std::string& pName = [&]() -> const std::string& { - auto nameIt = playerNameCache.find(playerGuid); - static const std::string kUnknown = "unknown"; - return (nameIt != playerNameCache.end()) ? nameIt->second : kUnknown; - }(); + static const std::string kUnknown = "unknown"; + auto nameIt = playerNameCache.find(playerGuid); + const std::string& pName = (nameIt != playerNameCache.end()) ? nameIt->second : kUnknown; const std::string& fmt = it->second; size_t pos = fmt.find("%s"); diff --git a/src/ui/talent_screen.cpp b/src/ui/talent_screen.cpp index b1231f24..e0598ad2 100644 --- a/src/ui/talent_screen.cpp +++ b/src/ui/talent_screen.cpp @@ -201,20 +201,23 @@ void TalentScreen::renderTalentTree(game::GameHandler& gameHandler, uint32_t tab return a->column < b->column; }); - // Find grid dimensions - uint8_t maxRow = 0, maxCol = 0; + // Find grid dimensions — use int to avoid uint8_t wrap-around infinite loops + int maxRow = 0, maxCol = 0; for (const auto* talent : talents) { - maxRow = std::max(maxRow, talent->row); - maxCol = std::max(maxCol, talent->column); + maxRow = std::max(maxRow, (int)talent->row); + maxCol = std::max(maxCol, (int)talent->column); } + // Sanity-cap to prevent runaway loops from corrupt/unexpected DBC data + maxRow = std::min(maxRow, 15); + maxCol = std::min(maxCol, 15); // WoW talent grids are always 4 columns wide if (maxCol < 3) maxCol = 3; const float iconSize = 40.0f; const float spacing = 8.0f; const float cellSize = iconSize + spacing; - const float gridWidth = (maxCol + 1) * cellSize + spacing; - const float gridHeight = (maxRow + 1) * cellSize + spacing; + const float gridWidth = (float)(maxCol + 1) * cellSize + spacing; + const float gridHeight = (float)(maxRow + 1) * cellSize + spacing; // Points in this tree uint32_t pointsInTree = 0; @@ -322,8 +325,8 @@ void TalentScreen::renderTalentTree(game::GameHandler& gameHandler, uint32_t tab } // Render talent icons - for (uint8_t row = 0; row <= maxRow; ++row) { - for (uint8_t col = 0; col <= maxCol; ++col) { + for (int row = 0; row <= maxRow; ++row) { + for (int col = 0; col <= maxCol; ++col) { const game::GameHandler::TalentEntry* talent = nullptr; for (const auto* t : talents) { if (t->row == row && t->column == col) {