More physics error checks, ragdoll clamps the velocity returned by PhysicsBody.CorrectPosition to prevent applying excessively high velocities to the collider if the position has changed significantly between frames

This commit is contained in:
Joonas Rikkonen
2018-07-23 17:58:02 +03:00
parent a373c589d1
commit 25a62b3a51
3 changed files with 58 additions and 18 deletions

View File

@@ -453,7 +453,7 @@ namespace Barotrauma
float newRotation = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 7);
bool awake = msg.ReadBoolean();
Vector2 newVelocity = Vector2.Zero;
if (awake)
{
newVelocity = new Vector2(
@@ -461,6 +461,19 @@ namespace Barotrauma
msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
}
if (!MathUtils.IsValid(newPosition) || !MathUtils.IsValid(newRotation) || !MathUtils.IsValid(newVelocity))
{
string errorMsg = "Received invalid position data for the item \"" + Name
+ "\" (position: " + newPosition + ", rotation: " + newRotation + ", velocity: " + newVelocity + ")";
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#endif
GameAnalyticsManager.AddErrorEventOnce("Item.ClientReadPosition:InvalidData" + ID,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
return;
}
if (body == null)
{
DebugConsole.ThrowError("Received a position update for an item with no physics body (" + Name + ")");
@@ -470,7 +483,7 @@ namespace Barotrauma
body.FarseerBody.Awake = awake;
if (body.FarseerBody.Awake)
{
if ((newVelocity - body.LinearVelocity).Length() > 8.0f) body.LinearVelocity = newVelocity;
if ((newVelocity - body.LinearVelocity).LengthSquared() > 8.0f * 8.0f) body.LinearVelocity = newVelocity;
}
else
{
@@ -490,11 +503,12 @@ namespace Barotrauma
if ((newPosition - SimPosition).Length() > body.LinearVelocity.Length() * 2.0f)
{
body.SetTransform(newPosition, newRotation);
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
if (body.SetTransform(newPosition, newRotation))
{
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
}
}
}

View File

@@ -1332,8 +1332,24 @@ namespace Barotrauma
character.AnimController.Anim = AnimController.Animation.None;
}
Collider.LinearVelocity = Vector2.Zero;
Collider.CorrectPosition(character.MemState, deltaTime, out overrideTargetMovement);
Vector2 newVelocity = overrideTargetMovement;
Vector2 newPosition = Collider.SimPosition;
Collider.CorrectPosition(character.MemState, deltaTime, out newVelocity, out newPosition);
newVelocity = newVelocity.ClampLength(100.0f);
if (!MathUtils.IsValid(newVelocity)) newVelocity = Vector2.Zero;
Collider.LinearVelocity = newVelocity;
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
if (distSqrd > 10.0f)
{
SetPosition(newPosition);
}
else if (distSqrd > 0.1f)
{
Collider.SetTransform(newPosition, Collider.Rotation);
overrideTargetMovement = newVelocity;
}
//unconscious/dead characters can't correct their position using AnimController movement
// -> we need to correct it manually
@@ -1451,10 +1467,18 @@ namespace Barotrauma
}
}
Collider.SetTransform(Collider.SimPosition + positionError, Collider.Rotation + rotationError);
foreach (Limb limb in Limbs)
float errorMagnitude = positionError.Length();
if (errorMagnitude > 0.01f)
{
limb.body.SetTransform(limb.body.SimPosition + positionError, limb.body.Rotation);
Collider.SetTransform(Collider.SimPosition + positionError, Collider.Rotation + rotationError);
if (errorMagnitude > 0.5f)
{
character.MemLocalState.Clear();
foreach (Limb limb in Limbs)
{
limb.body.SetTransform(limb.body.SimPosition + positionError, limb.body.Rotation);
}
}
}
}

View File

@@ -463,30 +463,32 @@ namespace Barotrauma
body.ApplyTorque(torque);
}
public void SetTransform(Vector2 simPosition, float rotation)
public bool SetTransform(Vector2 simPosition, float rotation)
{
System.Diagnostics.Debug.Assert(MathUtils.IsValid(simPosition));
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return;
if (!IsValidValue(rotation, "rotation")) return;
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false;
if (!IsValidValue(rotation, "rotation")) return false;
body.SetTransform(simPosition, rotation);
SetPrevTransform(simPosition, rotation);
return true;
}
public void SetTransformIgnoreContacts(Vector2 simPosition, float rotation)
public bool SetTransformIgnoreContacts(Vector2 simPosition, float rotation)
{
System.Diagnostics.Debug.Assert(MathUtils.IsValid(simPosition));
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return;
if (!IsValidValue(rotation, "rotation")) return;
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false;
if (!IsValidValue(rotation, "rotation")) return false;
body.SetTransformIgnoreContacts(ref simPosition, rotation);
SetPrevTransform(simPosition, rotation);
return true;
}
public void SetPrevTransform(Vector2 simPosition, float rotation)