From f2337aeaa7442845e74b979a2a3a33f5c821bbfa Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 13:07:34 -0700 Subject: [PATCH] physics: disable gravity when server sends SMSG_MOVE_GRAVITY_DISABLE SMSG_MOVE_GRAVITY_DISABLE/ENABLE now correctly set/clear the LEVITATING movement flag instead of passing flag=0. GameHandler::isGravityDisabled() reads the LEVITATING bit and is synced to CameraController each frame. When gravity is disabled the physics loop bleeds off downward velocity and skips gravity accumulation, so Levitate and similar effects actually float the player rather than letting them fall through the world. --- include/game/game_handler.hpp | 3 +++ include/rendering/camera_controller.hpp | 3 +++ src/core/application.cpp | 1 + src/game/game_handler.cpp | 6 ++++-- src/rendering/camera_controller.cpp | 10 ++++++++-- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 8b39d3d9..60afeb23 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1155,6 +1155,9 @@ public: bool isPlayerRooted() const { return (movementInfo.flags & static_cast(MovementFlags::ROOT)) != 0; } + bool isGravityDisabled() const { + return (movementInfo.flags & static_cast(MovementFlags::LEVITATING)) != 0; + } void dismount(); // Taxi / Flight Paths diff --git a/include/rendering/camera_controller.hpp b/include/rendering/camera_controller.hpp index 2c8baf3a..d42ec5c0 100644 --- a/include/rendering/camera_controller.hpp +++ b/include/rendering/camera_controller.hpp @@ -94,6 +94,7 @@ public: void setRunSpeedOverride(float speed) { runSpeedOverride_ = speed; } void setMovementRooted(bool rooted) { movementRooted_ = rooted; } bool isMovementRooted() const { return movementRooted_; } + void setGravityDisabled(bool disabled) { gravityDisabled_ = disabled; } void setMounted(bool m) { mounted_ = m; } void setMountHeightOffset(float offset) { mountHeightOffset_ = offset; } void setExternalFollow(bool enabled) { externalFollow_ = enabled; } @@ -272,6 +273,8 @@ private: float runSpeedOverride_ = 0.0f; // Server-driven root state: when true, block all horizontal movement input. bool movementRooted_ = false; + // Server-driven gravity disable (levitate/hover): skip gravity accumulation. + bool gravityDisabled_ = false; bool mounted_ = false; float mountHeightOffset_ = 0.0f; bool externalMoving_ = false; diff --git a/src/core/application.cpp b/src/core/application.cpp index 7de5e2d9..06c43ff5 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1010,6 +1010,7 @@ void Application::update(float deltaTime) { if (renderer && gameHandler && renderer->getCameraController()) { renderer->getCameraController()->setRunSpeedOverride(gameHandler->getServerRunSpeed()); renderer->getCameraController()->setMovementRooted(gameHandler->isPlayerRooted()); + renderer->getCameraController()->setGravityDisabled(gameHandler->isGravityDisabled()); } bool onTaxi = gameHandler && diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 5751f602..51fce186 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -5579,10 +5579,12 @@ void GameHandler::handlePacket(network::Packet& packet) { // ---- Player movement flag changes (server-pushed) ---- case Opcode::SMSG_MOVE_GRAVITY_DISABLE: - handleForceMoveFlagChange(packet, "GRAVITY_DISABLE", Opcode::CMSG_MOVE_GRAVITY_DISABLE_ACK, 0, true); + handleForceMoveFlagChange(packet, "GRAVITY_DISABLE", Opcode::CMSG_MOVE_GRAVITY_DISABLE_ACK, + static_cast(MovementFlags::LEVITATING), true); break; case Opcode::SMSG_MOVE_GRAVITY_ENABLE: - handleForceMoveFlagChange(packet, "GRAVITY_ENABLE", Opcode::CMSG_MOVE_GRAVITY_ENABLE_ACK, 0, true); + handleForceMoveFlagChange(packet, "GRAVITY_ENABLE", Opcode::CMSG_MOVE_GRAVITY_ENABLE_ACK, + static_cast(MovementFlags::LEVITATING), false); break; case Opcode::SMSG_MOVE_LAND_WALK: handleForceMoveFlagChange(packet, "LAND_WALK", Opcode::CMSG_MOVE_WATER_WALK_ACK, 0, false); diff --git a/src/rendering/camera_controller.cpp b/src/rendering/camera_controller.cpp index 1c5930b0..b8f4ce30 100644 --- a/src/rendering/camera_controller.cpp +++ b/src/rendering/camera_controller.cpp @@ -717,8 +717,14 @@ void CameraController::update(float deltaTime) { jumpBufferTimer -= physicsDeltaTime; coyoteTimer -= physicsDeltaTime; - // Apply gravity - verticalVelocity += gravity * physicsDeltaTime; + // Apply gravity (skip when server has disabled gravity, e.g. Levitate spell) + if (gravityDisabled_) { + // Float in place: bleed off any downward velocity, allow upward to decay slowly + if (verticalVelocity < 0.0f) verticalVelocity = 0.0f; + else verticalVelocity *= std::max(0.0f, 1.0f - 3.0f * physicsDeltaTime); + } else { + verticalVelocity += gravity * physicsDeltaTime; + } targetPos.z += verticalVelocity * physicsDeltaTime; } } else {