Prevent player snapping to WMO roofs when jumping inside buildings
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run

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.
This commit is contained in:
Kelsi 2026-02-23 11:03:18 -08:00
parent bf997e1900
commit 06979e5c5c

View file

@ -681,7 +681,10 @@ void CameraController::update(float deltaTime) {
if (terrainManager) { if (terrainManager) {
terrainH = terrainManager->getHeightAt(targetPos.x, targetPos.y); 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; float wmoNormalZ = 1.0f;
if (wmoRenderer) { if (wmoRenderer) {
wmoH = wmoRenderer->getFloorHeight(targetPos.x, targetPos.y, wmoProbeZ, &wmoNormalZ); wmoH = wmoRenderer->getFloorHeight(targetPos.x, targetPos.y, wmoProbeZ, &wmoNormalZ);
@ -692,6 +695,13 @@ void CameraController::update(float deltaTime) {
if (wmoH && wmoNormalZ < minWalkableWmo) { if (wmoH && wmoNormalZ < minWalkableWmo) {
wmoH = std::nullopt; // Treat as unwalkable 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; centerTerrainH = terrainH;
centerWmoH = wmoH; centerWmoH = wmoH;
@ -802,7 +812,8 @@ void CameraController::update(float deltaTime) {
{0.0f, WMO_FOOTPRINT}, {0.0f, -WMO_FOOTPRINT} {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; float minWalkableWmo = cachedInsideWMO ? MIN_WALKABLE_NORMAL_WMO : MIN_WALKABLE_NORMAL_TERRAIN;
for (const auto& o : wmoOffsets) { for (const auto& o : wmoOffsets) {
@ -811,6 +822,9 @@ void CameraController::update(float deltaTime) {
if (!wh) continue; if (!wh) continue;
if (nz < minWalkableWmo) 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. // Keep to nearby, walkable steps only.
if (*wh > targetPos.z + stepUpBudget) continue; if (*wh > targetPos.z + stepUpBudget) continue;
if (*wh < targetPos.z - 2.5f) continue; if (*wh < targetPos.z - 2.5f) continue;