(38b5d9aad) Experimental changes to syncing ragdolled (unconscious/dead) characters: - Higher error tolerance when syncing the positions. It's often hard to get the main limb exactly to the same position as the collider, because the positions of the limbs aren't synced and the pose of the ragdoll may differ between the server and clients. Increasing the tolerance makes it less likely for dead/unconscious characters to "twitch" when the game attempts to force the main limb to the position of the collider. - If the position of the ragdoll differs from the position of the collider so much that CheckDistFromCollider disables limb collisions, apply an additional force to all limbs to force the ragdoll to the correct position. Otherwise the ragdoll can occasionally start "hanging" midair, clipping through solid objects, because the main limb's pull joint doesn't necessarily have enough force to pull the entire ragdoll up to the collider.

This commit is contained in:
Joonas Rikkonen
2019-04-01 22:47:03 +03:00
parent 11f2bf4b38
commit ec7e23061b
130 changed files with 1359 additions and 2352 deletions
@@ -369,18 +369,9 @@ namespace Barotrauma
return;
}
Vector2 transformedMovement = reverse ? -movement : movement;
float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2;
float mainLimbAngle = 0;
if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
{
mainLimbAngle = TorsoAngle.Value;
}
else if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
mainLimbAngle = HeadAngle.Value;
}
mainLimbAngle *= Dir;
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2;
float mainLimbAngle = (MainLimb.type == LimbType.Torso ? TorsoAngle.Value : HeadAngle.Value) * Dir;
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi)
{
movementAngle += MathHelper.TwoPi;
@@ -388,7 +379,7 @@ namespace Barotrauma
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi)
{
movementAngle -= MathHelper.TwoPi;
}
}
if (CurrentSwimParams.RotateTowardsMovement)
{
@@ -412,6 +403,7 @@ namespace Barotrauma
if (TailAngle.HasValue)
{
Limb tail = GetLimb(LimbType.Tail);
//tail?.body.SmoothRotate(movementAngle + TailAngle.Value * Dir, TailTorque);
if (tail != null)
{
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
@@ -421,10 +413,6 @@ namespace Barotrauma
else
{
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
if (reverse)
{
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
}
if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
@@ -454,7 +442,7 @@ namespace Barotrauma
var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude);
if (waveLength > 0 && waveAmplitude > 0)
{
WalkPos -= transformedMovement.Length() / Math.Abs(waveLength);
WalkPos -= movement.Length() / Math.Abs(waveLength);
WalkPos = MathUtils.WrapAngleTwoPi(WalkPos);
}
@@ -697,6 +685,12 @@ namespace Barotrauma
limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength);
}
while (referenceLimb.Rotation - angle < -MathHelper.TwoPi)
{
angle -= MathHelper.TwoPi;
}
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
}
private void SmoothRotateWithoutWrapping(Limb limb, float angle, Limb referenceLimb, float torque)
@@ -1463,6 +1463,11 @@ namespace Barotrauma
targetRightHand.PullJointMaxForce = 5000.0f;
}
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
Collider.ResetDynamics();
}
target.AnimController.IgnorePlatforms = true;
}
else
@@ -99,7 +99,7 @@ namespace Barotrauma
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/";
public static string GetDefaultFile(string speciesName, AnimationType animType) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName, animType)}.xml";
public static string GetFolder(string speciesName)
protected static string GetFolder(string speciesName)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
@@ -79,7 +79,7 @@ namespace Barotrauma
new XAttribute("sourcerect", $"0, 0, 1, 1")))
};
public static string GetFolder(string speciesName)
protected static string GetFolder(string speciesName)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
@@ -1035,6 +1035,8 @@ namespace Barotrauma
CheckValidity();
CheckValidity();
UpdateNetPlayerPosition(deltaTime);
CheckDistFromCollider();
UpdateCollisionCategories();
@@ -1295,42 +1297,17 @@ namespace Barotrauma
UpdateProjSpecific(deltaTime);
}
public bool Invalid { get; private set; }
private int validityResets;
private bool CheckValidity()
private void CheckValidity()
{
bool isColliderValid = CheckValidity(Collider);
bool limbsValid = true;
CheckValidity(Collider);
foreach (Limb limb in limbs)
{
if (limb.body == null || !limb.body.Enabled) { continue; }
if (!CheckValidity(limb.body))
{
limbsValid = false;
break;
}
CheckValidity(limb.body);
}
bool isValid = isColliderValid && limbsValid;
if (!isValid)
{
validityResets++;
if (validityResets > 1)
{
Invalid = true;
DebugConsole.ThrowError("Invalid ragdoll physics. Ragdoll freezed to prevent crashes.");
Collider.SetTransform(Vector2.Zero, 0.0f);
foreach (Limb limb in Limbs)
{
limb.body.SetTransform(Collider.SimPosition, 0.0f);
limb.body.ResetDynamics();
}
Frozen = true;
}
}
return isValid;
}
private bool CheckValidity(PhysicsBody body)
private void CheckValidity(PhysicsBody body)
{
string errorMsg = null;
string bodyName = body.UserData is Limb ? "Limb" : "Collider";
@@ -1382,7 +1359,7 @@ namespace Barotrauma
limb.body.ResetDynamics();
}
SetInitialLimbPositions();
return false;
return;
}
return true;
}
@@ -1524,7 +1501,8 @@ namespace Barotrauma
float allowedDist = Math.Max(Math.Max(Collider.radius, Collider.width), Collider.height) * 2.0f;
float resetDist = allowedDist * 5.0f;
float distSqrd = Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition);
Vector2 diff = Collider.SimPosition - MainLimb.SimPosition;
float distSqrd = diff.LengthSquared();
if (distSqrd > resetDist * resetDist)
{
@@ -1535,10 +1513,13 @@ namespace Barotrauma
{
//ragdoll too far from the collider, disable collisions until it's close enough
//(in case the ragdoll has gotten stuck somewhere)
Vector2 forceDir = diff / (float)Math.Sqrt(distSqrd);
foreach (Limb limb in Limbs)
{
if (limb.IsSevered) continue;
limb.body.CollidesWith = Physics.CollisionNone;
limb.body.ApplyForce(forceDir * limb.Mass * 10.0f, maxVelocity: 10.0f);
}
collisionsDisabled = true;