From 06979e5c5cc3ffc3fb4de4201ad195da64a74b68 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Feb 2026 11:03:18 -0800 Subject: [PATCH] Prevent player snapping to WMO roofs when jumping inside buildings Anchor WMO floor probe to last ground Z when airborne so the detection ceiling doesn't rise with the jump and catch roof/ceiling geometry. --- src/rendering/camera_controller.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/rendering/camera_controller.cpp b/src/rendering/camera_controller.cpp index 115c2970..9dbc2b71 100644 --- a/src/rendering/camera_controller.cpp +++ b/src/rendering/camera_controller.cpp @@ -681,7 +681,10 @@ void CameraController::update(float deltaTime) { if (terrainManager) { terrainH = terrainManager->getHeightAt(targetPos.x, targetPos.y); } - float wmoProbeZ = std::max(targetPos.z, lastGroundZ) + stepUpBudget + 0.5f; + // When airborne, anchor probe to last ground level so the + // ceiling doesn't rise with the jump and catch roof geometry. + float wmoBaseZ = grounded ? std::max(targetPos.z, lastGroundZ) : lastGroundZ; + float wmoProbeZ = wmoBaseZ + stepUpBudget + 0.5f; float wmoNormalZ = 1.0f; if (wmoRenderer) { wmoH = wmoRenderer->getFloorHeight(targetPos.x, targetPos.y, wmoProbeZ, &wmoNormalZ); @@ -692,6 +695,13 @@ void CameraController::update(float deltaTime) { if (wmoH && wmoNormalZ < minWalkableWmo) { wmoH = std::nullopt; // Treat as unwalkable } + + // Reject WMO floors far above last known ground when airborne + // (prevents snapping to roof/ceiling surfaces during jumps) + if (wmoH && !grounded && *wmoH > lastGroundZ + stepUpBudget + 0.5f) { + wmoH = std::nullopt; + centerWmoH = std::nullopt; + } centerTerrainH = terrainH; centerWmoH = wmoH; @@ -802,7 +812,8 @@ void CameraController::update(float deltaTime) { {0.0f, WMO_FOOTPRINT}, {0.0f, -WMO_FOOTPRINT} }; - float wmoProbeZ = std::max(targetPos.z, lastGroundZ) + stepUpBudget + 0.6f; + float wmoMultiBaseZ = grounded ? std::max(targetPos.z, lastGroundZ) : lastGroundZ; + float wmoProbeZ = wmoMultiBaseZ + stepUpBudget + 0.6f; float minWalkableWmo = cachedInsideWMO ? MIN_WALKABLE_NORMAL_WMO : MIN_WALKABLE_NORMAL_TERRAIN; for (const auto& o : wmoOffsets) { @@ -811,6 +822,9 @@ void CameraController::update(float deltaTime) { if (!wh) continue; if (nz < minWalkableWmo) continue; + // Reject roof/ceiling surfaces when airborne + if (!grounded && *wh > lastGroundZ + stepUpBudget + 0.5f) continue; + // Keep to nearby, walkable steps only. if (*wh > targetPos.z + stepUpBudget) continue; if (*wh < targetPos.z - 2.5f) continue;