fix(Core/Entities): Knock back players if they are not under client control. (#26540)

Co-authored-by: Claude <claude@users.noreply.github.com>
Co-authored-by: sogladev <sogladev@gmail.com>
This commit is contained in:
Benjamin Jackson
2026-07-10 11:36:22 -04:00
committed by GitHub
parent edb3730f7a
commit ac071f8f5d
3 changed files with 24 additions and 7 deletions

View File

@@ -15417,10 +15417,12 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
}
}
if (!player)
{
// While feared/confused the client has no control over the unit,
// so a SMSG_MOVE_KNOCK_BACK would be ignored or immediately overridden by the server
// side fleeing/confused splines. Perform the knockback server side instead; the
// fleeing/confused movement generator resumes once this spline is finalized
if (!player || !IsClientControlled())
GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ);
}
else
{
float vcos, vsin;

View File

@@ -840,14 +840,20 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData)
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
mover->m_movementInfo = movementInfo;
// Relocate the mover to the acknowledged position. Otherwise the server (and the
// MSG_MOVE_KNOCK_BACK broadcast below) keeps using the pre-knockback position until
// the next regular movement packet arrives, desyncing the unit for nearby clients
if (!ProcessMovementInfo(movementInfo, mover, mover->ToPlayer(), recvData))
{
recvData.rfinish(); // prevent warnings spam
return;
}
if (mover->IsPlayer() && static_cast<Player*>(mover)->IsFreeFlying())
mover->SetCanFly(true);
WorldPacket data(MSG_MOVE_KNOCK_BACK, 66);
data << guid.WriteAsPacked();
_player->m_mover->BuildMovementPacket(&data);
WriteMovementInfo(&data, &movementInfo);
_player->SetCanTeleport(true);
// knockback specific info
data << movementInfo.jump.sinAngle;

View File

@@ -620,7 +620,7 @@ void MotionMaster::MoveTakeoff(uint32 id, float x, float y, float z, float speed
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
{
//this function may make players fall below map
if (_owner->IsPlayer())
if (_owner->IsPlayer() && _owner->IsClientControlled())
return;
if (speedXY <= 0.1f)
@@ -640,6 +640,15 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
init.SetOrientationFixed(true);
init.SetVelocity(speedXY);
// Do not mutate an active fleeing/confused movement generator,
// doing so breaks the movement upon landing from the knockback
MovementGeneratorType slotType = GetMotionSlotType(MOTION_SLOT_CONTROLLED);
if (slotType == FLEEING_MOTION_TYPE || slotType == CONFUSED_MOTION_TYPE)
{
init.Launch();
return;
}
Mutate(new EffectMovementGenerator(init, 0), MOTION_SLOT_CONTROLLED);
}