physics: implement knockback simulation from SMSG_MOVE_KNOCK_BACK

Previously the handler ACKed with current position and ignored the
velocity fields entirely (vcos/vsin/hspeed/vspeed were [[maybe_unused]]).
The server expects the client to fly through the air on knockback — without
simulation the player stays in place while the server models them as airborne,
causing position desync and rubberbanding.

Changes:
- CameraController: add applyKnockBack(vcos, vsin, hspeed, vspeed)
  that sets knockbackHorizVel_ and launches verticalVelocity = -vspeed
  (server sends vspeed as negative for upward launches, matching TrinityCore)
- Physics loop: each tick adds knockbackHorizVel_ to targetPos then applies
  exponential drag (KNOCKBACK_HORIZ_DRAG=4.5/s) until velocity < 0.05 u/s
- GameHandler: parse all four fields, add KnockBackCallback, call it for
  the local player so the camera controller receives the impulse
- Application: register the callback — routes server knockback to physics

The existing ACK path is unchanged; the server gets position confirmation
as before while the client now actually simulates the trajectory.
This commit is contained in:
Kelsi 2026-03-10 12:28:11 -07:00
parent dd3f9e5b9e
commit c622fde7be
5 changed files with 67 additions and 5 deletions

View file

@ -103,6 +103,12 @@ public:
// Trigger mount jump (applies vertical velocity for physics hop)
void triggerMountJump();
// Apply server-driven knockback impulse.
// dir: render-space 2D direction unit vector (from vcos/vsin in packet)
// hspeed: horizontal speed magnitude (units/s)
// vspeed: raw packet vspeed field (server sends negative for upward launch)
void applyKnockBack(float vcos, float vsin, float hspeed, float vspeed);
// For first-person player hiding
void setCharacterRenderer(class CharacterRenderer* cr, uint32_t playerId) {
characterRenderer = cr;
@ -313,6 +319,14 @@ private:
float cachedFloorHeight_ = 0.0f;
bool hasCachedFloor_ = false;
static constexpr float COLLISION_CACHE_DISTANCE = 0.15f; // Re-check every 15cm
// Server-driven knockback state.
// When the server sends SMSG_MOVE_KNOCK_BACK, we apply horizontal + vertical
// impulse here and let the normal physics loop (gravity, collision) resolve it.
bool knockbackActive_ = false;
glm::vec2 knockbackHorizVel_ = glm::vec2(0.0f); // render-space horizontal velocity (units/s)
// Horizontal velocity decays via WoW-like drag so the player doesn't slide forever.
static constexpr float KNOCKBACK_HORIZ_DRAG = 4.5f; // exponential decay rate (1/s)
};
} // namespace rendering