(8e2e6e4da) Physics error prevention: - Use the ApplyForce/ApplyImpulse method overrides that clamp the resulting velocity to a value (in this case NetConfig.MaxPhysicsBodyVelocity, 64 m/s). Without this, explosions and attacks for example could apply arbitrarily large forces to bodies, causing physics errors in Ragdoll.CheckValidity. - Make sure angular velocity still has a sane value after applying an impulse to a specific point of a collider.

This commit is contained in:
Joonas Rikkonen
2019-04-03 16:21:22 +03:00
parent 5d7dba0f70
commit 0844f1eae4
12 changed files with 87 additions and 39 deletions
@@ -587,11 +587,16 @@ namespace Barotrauma
if (!IsValidValue(impulse / body.Mass, "new velocity")) return;
if (!IsValidValue(impulse, "impulse", -1e10f, 1e10f)) return;
if (!IsValidValue(maxVelocity, "max velocity")) return;
float currSpeed = body.LinearVelocity.Length();
Vector2 velocityAddition = impulse / Mass;
Vector2 newVelocity = body.LinearVelocity + velocityAddition;
newVelocity = newVelocity.ClampLength(Math.Max(currSpeed, maxVelocity));
float newSpeedSqr = newVelocity.LengthSquared();
if (newSpeedSqr > maxVelocity * maxVelocity)
{
newVelocity = newVelocity.ClampLength(maxVelocity);
}
if (!IsValidValue((newVelocity - body.LinearVelocity), "new velocity", -1000.0f, 1000.0f)) return;
body.ApplyLinearImpulse((newVelocity - body.LinearVelocity) * Mass);
}
@@ -600,10 +605,36 @@ namespace Barotrauma
{
if (!IsValidValue(impulse, "impulse", -1e10f, 1e10f)) return;
if (!IsValidValue(point, "point")) return;
if (!IsValidValue(impulse / body.Mass, "new velocity")) return;
if (!IsValidValue(impulse / body.Mass, "new velocity", -1000.0f, 1000.0f)) return;
body.ApplyLinearImpulse(impulse, point);
}
/// <summary>
/// Apply an impulse to the body without increasing it's velocity above a specific limit.
/// </summary>
public void ApplyLinearImpulse(Vector2 impulse, Vector2 point, float maxVelocity)
{
if (!IsValidValue(impulse, "impulse", -1e10f, 1e10f)) return;
if (!IsValidValue(point, "point")) return;
if (!IsValidValue(maxVelocity, "max velocity")) return;
Vector2 velocityAddition = impulse / Mass;
Vector2 newVelocity = body.LinearVelocity + velocityAddition;
float newSpeedSqr = newVelocity.LengthSquared();
if (newSpeedSqr > maxVelocity * maxVelocity)
{
newVelocity = newVelocity.ClampLength(maxVelocity);
}
if (!IsValidValue((newVelocity - body.LinearVelocity), "new velocity", -1000.0f, 1000.0f)) return;
body.ApplyLinearImpulse((newVelocity - body.LinearVelocity) * Mass, point);
body.AngularVelocity = MathHelper.Clamp(
body.AngularVelocity,
-NetConfig.MaxPhysicsBodyAngularVelocity,
NetConfig.MaxPhysicsBodyAngularVelocity);
}
public void ApplyForce(Vector2 force)
{
if (!IsValidValue(force, "force", -1e10f, 1e10f)) return;
@@ -618,11 +649,14 @@ namespace Barotrauma
if (!IsValidValue(force, "force", -1e10f, 1e10f)) return;
if (!IsValidValue(maxVelocity, "max velocity")) return;
float currSpeed = body.LinearVelocity.Length();
Vector2 velocityAddition = force / Mass * (float)Timing.Step;
Vector2 newVelocity = body.LinearVelocity + velocityAddition;
newVelocity = newVelocity.ClampLength(Math.Max(currSpeed, maxVelocity));
float newSpeedSqr = newVelocity.LengthSquared();
if (newSpeedSqr > maxVelocity * maxVelocity)
{
newVelocity = newVelocity.ClampLength(maxVelocity);
}
body.ApplyForce((newVelocity - body.LinearVelocity) * Mass / (float)Timing.Step);
}
@@ -725,17 +759,19 @@ namespace Barotrauma
Vector2 dragForce = Vector2.Zero;
if (LinearVelocity.LengthSquared() > 0.00001f)
float speedSqr = LinearVelocity.LengthSquared();
if (speedSqr > 0.00001f)
{
//drag
Vector2 velDir = Vector2.Normalize(LinearVelocity);
float speed = (float)Math.Sqrt(speedSqr);
Vector2 velDir = LinearVelocity / speed;
float vel = LinearVelocity.Length() * 2.0f;
float vel = speed * 2.0f;
float drag = vel * vel * Math.Max(height + radius * 2, height);
dragForce = Math.Min(drag, Mass * 500.0f) * -velDir;
dragForce = Math.Min(drag, Mass * 500.0f) * -velDir;
}
ApplyForce(dragForce + buoyancy);
ApplyForce(dragForce + buoyancy, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
ApplyTorque(body.AngularVelocity * body.Mass * -0.08f);
}