mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-22 12:42:49 +00:00
feat: server side knockback for AI moved objects
The client only simulates knockbacks on the character it controls (LWOControllablePhysComponent::msgKnockback); enemies and NPCs are drawn where the server puts them, so a knockback on them did nothing and scripts stunned them instead. MovementAIComponent::Knockback now flies the object the way the client flies its character: a vector longer than 5 lifts it 0.5, throws it with that velocity under WorldConfig gravity (times its gravity scale) until it lands on the navmesh, no sooner than 250ms later; a shorter one moves it by the vector. Walls taller than a step stop sideways motion, the landing is put back onto the navmesh, and pathing and the combat AI wait until it lands (destinations set mid air are walked to afterwards). Position and velocity go out in the normal serialization every tick. KnockbackBehavior builds the vector like the client's Cast (strength capped at 300, angle as elevation, relative, caster and ignore_self) and knocks back server moved targets that aren't immune, both when the server casts and when a client's skill hits. The blocked bit it writes now also answers for the target's knockback immunity, so a player whose client hasn't caught up with a Personal Fortress isn't knocked out of it. The AM shield generators knock enemies back like live instead of stunning them. Fixes #257 Refs #185 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "Zone.h"
|
||||
#include "dpKnockback.h"
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
class ControllablePhysicsComponent;
|
||||
@@ -223,8 +225,31 @@ public:
|
||||
bool HasPath() const { return m_Path != nullptr; }
|
||||
|
||||
void FollowTarget(const LWOOBJID target);
|
||||
|
||||
/**
|
||||
* Knocks this entity back the way the client knocks back the character it controls (the Knockback game
|
||||
* message): a vector longer than dpKnockback::MIN_LAUNCH_SPEED throws it in an arc under the zone's gravity
|
||||
* until it lands on the navmesh, a shorter one moves it by the vector. Pathing waits until it lands.
|
||||
* @param vector the knockback velocity
|
||||
*/
|
||||
void Knockback(const NiPoint3& vector);
|
||||
|
||||
/**
|
||||
* Returns whether this entity is flying from a knockback
|
||||
*/
|
||||
bool IsKnockedBack() const { return m_Knockback.IsActive(); }
|
||||
private:
|
||||
|
||||
/**
|
||||
* Moves the entity along its knockback arc, landing it when it reaches the ground
|
||||
*/
|
||||
void UpdateKnockback(float deltaTime);
|
||||
|
||||
/**
|
||||
* The height of the ground under a point: the navmesh if the zone has one, else the height the knockback started at
|
||||
*/
|
||||
float GetGroundHeight(const NiPoint3& point) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Runs the commands on a waypoint if a path exists
|
||||
@@ -348,6 +373,21 @@ private:
|
||||
uint32_t m_CurrentPathWaypointCount{ 0 };
|
||||
|
||||
LWOOBJID m_FollowedTarget{ LWOOBJID_EMPTY };
|
||||
|
||||
/**
|
||||
* The knockback this entity is flying through, if any
|
||||
*/
|
||||
dpKnockback::Arc m_Knockback;
|
||||
|
||||
/**
|
||||
* The height the knockback started at, the ground used when the zone has no navmesh
|
||||
*/
|
||||
float m_KnockbackStartHeight{};
|
||||
|
||||
/**
|
||||
* A destination set while flying, walked to after landing
|
||||
*/
|
||||
std::optional<NiPoint3> m_DestinationAfterKnockback;
|
||||
};
|
||||
|
||||
#endif // MOVEMENTAICOMPONENT_H
|
||||
|
||||
Reference in New Issue
Block a user