mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-27 22:16:11 +00:00
fix(Core/Movement): Prevent Follow predictions from clipping through walls and add teleport as last resort (#24287)
This commit is contained in:
@@ -461,8 +461,7 @@ static Optional<float> GetVelocity(Unit* owner, Unit* target, G3D::Vector3 const
|
||||
static Position const PredictPosition(Unit* target)
|
||||
{
|
||||
Position pos = target->GetPosition();
|
||||
|
||||
// 0.5 - it's time (0.5 sec) between starting movement opcode (e.g. MSG_MOVE_START_FORWARD) and MSG_MOVE_HEARTBEAT sent by client
|
||||
// 0.5 - it's time (0.5 sec) between starting movement opcode (e.g. MSG_MOVE_START_FORWARD) and MSG_MOVE_HEARTBEAT sent by client
|
||||
float speed = target->GetSpeed(Movement::SelectSpeedType(target->GetUnitMovementFlags())) * 0.5f;
|
||||
float orientation = target->GetOrientation();
|
||||
|
||||
@@ -491,6 +490,20 @@ static Position const PredictPosition(Unit* target)
|
||||
return pos;
|
||||
}
|
||||
|
||||
static bool IsValidPredictedPosition(Unit* target, Position const& predicted)
|
||||
{
|
||||
Position current = target->GetPosition();
|
||||
|
||||
if (current.GetExactDist2d(&predicted) > 15.0f)
|
||||
return false;
|
||||
|
||||
// Check line of sight from current to predicted to avoid clipping through geometry
|
||||
if (!target->IsWithinLOS(predicted.GetPositionX(), predicted.GetPositionY(), predicted.GetPositionZ()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool FollowMovementGenerator<T>::PositionOkay(Unit* target, bool isPlayerPet, bool& targetIsMoving, uint32 diff)
|
||||
{
|
||||
@@ -571,7 +584,10 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
; // closes "bool forceDest", that way it is more appropriate, so we can comment out crap whenever we need to
|
||||
|
||||
bool targetIsMoving = false;
|
||||
if (PositionOkay(target, owner->IsGuardian() && target->IsPlayer(), targetIsMoving, time_diff))
|
||||
bool isPlayerPet = owner->IsGuardian() && target->IsPlayer();
|
||||
bool isFollowingPlayer = target->IsPlayer();
|
||||
|
||||
if (PositionOkay(target, isPlayerPet, targetIsMoving, time_diff))
|
||||
{
|
||||
if (owner->HasUnitState(UNIT_STATE_FOLLOW_MOVE) && owner->movespline->Finalized())
|
||||
{
|
||||
@@ -599,14 +615,23 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
if (_lastPredictedPosition && _lastPredictedPosition->GetExactDistSq(&predictedPosition) < 0.25f)
|
||||
return true;
|
||||
|
||||
_lastPredictedPosition = predictedPosition;
|
||||
targetPosition = predictedPosition;
|
||||
i_recheckPredictedDistance = true;
|
||||
if (IsValidPredictedPosition(target, predictedPosition))
|
||||
{
|
||||
_lastPredictedPosition = predictedPosition;
|
||||
targetPosition = predictedPosition;
|
||||
i_recheckPredictedDistance = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastPredictedPosition.reset();
|
||||
i_recheckPredictedDistance = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i_recheckPredictedDistance = false;
|
||||
i_recheckPredictedDistanceTimer.Reset(0);
|
||||
_lastPredictedPosition.reset();
|
||||
}
|
||||
|
||||
if (!i_path)
|
||||
@@ -628,6 +653,22 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
if (!owner->IsStopped())
|
||||
owner->StopMoving();
|
||||
|
||||
// Teleport if stuck and too far away
|
||||
if (cOwner && isFollowingPlayer)
|
||||
{
|
||||
float distance = owner->GetDistance(target);
|
||||
if (distance > 20.f)
|
||||
{
|
||||
float teleX;
|
||||
float teleY;
|
||||
float teleZ;
|
||||
|
||||
target->GetClosePoint(teleX, teleY, teleZ, owner->GetCombatReach());
|
||||
owner->NearTeleportTo(teleX, teleY, teleZ, target->GetOrientation());
|
||||
_lastTargetPosition.reset();
|
||||
_lastPredictedPosition.reset();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class FollowMovementGenerator : public MovementGeneratorMedium<T, FollowMovement
|
||||
{
|
||||
public:
|
||||
FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, bool inheritWalkState, bool inheritSpeed)
|
||||
: TargetedMovementGeneratorBase(target), i_path(nullptr), i_recheckPredictedDistanceTimer(0), i_recheckPredictedDistance(false), _range(range), _angle(angle),_inheritWalkState(inheritWalkState), _inheritSpeed(inheritSpeed) {}
|
||||
: TargetedMovementGeneratorBase(target), i_path(nullptr), i_recheckPredictedDistanceTimer(0), i_recheckPredictedDistance(false), _range(range), _angle(angle), _inheritWalkState(inheritWalkState), _inheritSpeed(inheritSpeed) {}
|
||||
~FollowMovementGenerator() { }
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
|
||||
|
||||
Reference in New Issue
Block a user