Fixes to unconscious character pos syncing:

- main limb is anchored to collider
- server ignores inputs from unconscious characters and doesn't freeze them
- using timestamp-based interpolation on the client's own character instead of IDs
This commit is contained in:
Regalis
2017-01-03 23:49:37 +02:00
parent 1eea373117
commit bb685019a2
5 changed files with 81 additions and 58 deletions
@@ -59,7 +59,7 @@ namespace Barotrauma
ColliderIndex = Crouching ? 1 : 0; ColliderIndex = Crouching ? 1 : 0;
if (!Crouching && ColliderIndex == 1) Crouching = true; if (!Crouching && ColliderIndex == 1) Crouching = true;
if (character.IsDead || character.IsUnconscious || stunTimer > 0.0f) if (!character.AllowMovement)
{ {
levitatingCollider = false; levitatingCollider = false;
Collider.FarseerBody.FixedRotation = false; Collider.FarseerBody.FixedRotation = false;
@@ -921,13 +921,15 @@ namespace Barotrauma
target.AnimController.IgnorePlatforms = IgnorePlatforms; target.AnimController.IgnorePlatforms = IgnorePlatforms;
if (target.Stun > 0.0f || target.IsUnconscious || target.IsDead) if (!target.AllowMovement)
{ {
target.AnimController.TargetMovement = TargetMovement; target.AnimController.TargetMovement = TargetMovement;
} }
else if (target is AICharacter) else if (target is AICharacter)
{ {
target.AnimController.TargetMovement = Vector2.Lerp(target.AnimController.TargetMovement, (character.SimPosition + Vector2.UnitX * Dir) - target.SimPosition, 0.5f); target.AnimController.TargetMovement = Vector2.Lerp(
target.AnimController.TargetMovement,
(character.SimPosition + Vector2.UnitX * Dir) - target.SimPosition, 0.5f);
} }
} }
@@ -1171,11 +1171,19 @@ namespace Barotrauma
protected void CheckDistFromCollider() protected void CheckDistFromCollider()
{ {
float allowedDist = Math.Max(Math.Max(Collider.radius, Collider.width), Collider.height) * 2.0f; float allowedDist = Math.Max(Math.Max(Collider.radius, Collider.width), Collider.height) * 2.0f;
float resetDist = allowedDist * 10.0f;
//if the ragdoll is too far from the collider, disable collisions until it's close enough float distSqrd = Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition);
//(in case the ragdoll has gotten stuck somewhere)
if (Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition) > allowedDist*allowedDist) if (distSqrd > resetDist * resetDist)
{ {
//ragdoll way too far, reset position
SetPosition(Collider.SimPosition, true);
}
if (distSqrd > allowedDist * allowedDist)
{
//ragdoll too far from the collider, disable collisions until it's close enough
//(in case the ragdoll has gotten stuck somewhere)
foreach (Limb limb in Limbs) foreach (Limb limb in Limbs)
{ {
limb.body.CollidesWith = Physics.CollisionNone; limb.body.CollidesWith = Physics.CollisionNone;
@@ -1197,20 +1205,31 @@ namespace Barotrauma
{ {
if (GameMain.NetworkMember == null) return; if (GameMain.NetworkMember == null) return;
if (character != GameMain.NetworkMember.Character || if (character != GameMain.NetworkMember.Character || !character.AllowMovement)
character.IsUnconscious || character.Stun > 0.0f)
{ {
//use simple interpolation for other players' characters and unconscious characters //use simple interpolation for other players' characters and characters that can't move
if (character.MemPos.Count > 0) if (character.MemPos.Count > 0)
{ {
Collider.LinearVelocity = Vector2.Zero; Collider.LinearVelocity = Vector2.Zero;
Collider.CorrectPosition(character.MemPos, deltaTime, out overrideTargetMovement); Collider.CorrectPosition(character.MemPos, deltaTime, out overrideTargetMovement);
//unconscious/dead characters can't correct their position using AnimController movement
// -> we need to correct it manually
if (character.AllowMovement)
{
Collider.LinearVelocity = overrideTargetMovement;
MainLimb.pullJoint.WorldAnchorB = Collider.SimPosition;
MainLimb.pullJoint.Enabled = true;
}
} }
character.MemLocalPos.Clear();
} }
else else
{ {
if (character.MemPos.Count < 1) return; if (character.MemPos.Count < 1) return;
overrideTargetMovement = Vector2.Zero;
PosInfo serverPos = character.MemPos.Last(); PosInfo serverPos = character.MemPos.Last();
int localPosIndex = character.MemLocalPos.FindIndex(m => m.ID == serverPos.ID); int localPosIndex = character.MemLocalPos.FindIndex(m => m.ID == serverPos.ID);
+34 -38
View File
@@ -211,6 +211,11 @@ namespace Barotrauma
} }
} }
public bool AllowMovement
{
get { return !IsUnconscious && Stun <= 0.0f && !isDead; }
}
public Vector2 CursorPosition public Vector2 CursorPosition
{ {
get { return cursorPosition; } get { return cursorPosition; }
@@ -1302,7 +1307,7 @@ namespace Barotrauma
if (this != Character.Controlled) if (this != Character.Controlled)
{ {
if (GameMain.Server != null && !(this is AICharacter)) if (GameMain.Server != null && !(this is AICharacter) && AllowMovement)
{ {
if (memInput.Count > 0) if (memInput.Count > 0)
{ {
@@ -1333,41 +1338,37 @@ namespace Barotrauma
{ {
isStillCountdown = 15; isStillCountdown = 15;
} }
//DebugConsole.NewMessage(Convert.ToString(memInput.Count), Color.Lime);
} }
else else
{ {
AnimController.Frozen = true; if (AllowMovement) AnimController.Frozen = true;
return; return;
} }
} }
} }
else else if (GameMain.Client != null)
{ {
if (GameMain.Client != null) memLocalPos.Add(new PosInfo(SimPosition, AnimController.TargetDir, LastNetworkUpdateID));
InputNetFlags newInput = InputNetFlags.None;
if (IsKeyDown(InputType.Left)) newInput |= InputNetFlags.Left;
if (IsKeyDown(InputType.Right)) newInput |= InputNetFlags.Right;
if (IsKeyDown(InputType.Up)) newInput |= InputNetFlags.Up;
if (IsKeyDown(InputType.Down)) newInput |= InputNetFlags.Down;
if (IsKeyDown(InputType.Run)) newInput |= InputNetFlags.Run;
if (IsKeyDown(InputType.Select)) newInput |= InputNetFlags.Select;
if (IsKeyDown(InputType.Use)) newInput |= InputNetFlags.Use;
if (IsKeyDown(InputType.Aim)) newInput |= InputNetFlags.Aim;
if (AnimController.TargetDir == Direction.Left) newInput |= InputNetFlags.FacingLeft;
memInput.Insert(0, newInput);
memMousePos.Insert(0, closestItem!=null ? closestItem.Position : cursorPosition);
LastNetworkUpdateID++;
if (memInput.Count > 60)
{ {
memLocalPos.Add(new PosInfo(SimPosition, AnimController.TargetDir, LastNetworkUpdateID)); memInput.RemoveRange(60, memInput.Count - 60);
memMousePos.RemoveRange(60, memMousePos.Count - 60);
InputNetFlags newInput = InputNetFlags.None;
if (IsKeyDown(InputType.Left)) newInput |= InputNetFlags.Left;
if (IsKeyDown(InputType.Right)) newInput |= InputNetFlags.Right;
if (IsKeyDown(InputType.Up)) newInput |= InputNetFlags.Up;
if (IsKeyDown(InputType.Down)) newInput |= InputNetFlags.Down;
if (IsKeyDown(InputType.Run)) newInput |= InputNetFlags.Run;
if (IsKeyDown(InputType.Select)) newInput |= InputNetFlags.Select;
if (IsKeyDown(InputType.Use)) newInput |= InputNetFlags.Use;
if (IsKeyDown(InputType.Aim)) newInput |= InputNetFlags.Aim;
if (AnimController.TargetDir == Direction.Left) newInput |= InputNetFlags.FacingLeft;
memInput.Insert(0, newInput);
memMousePos.Insert(0, closestItem!=null ? closestItem.Position : cursorPosition);
LastNetworkUpdateID++;
if (memInput.Count > 60)
{
memInput.RemoveRange(60, memInput.Count - 60);
memMousePos.RemoveRange(60, memMousePos.Count - 60);
}
} }
} }
@@ -2113,27 +2114,22 @@ namespace Barotrauma
facingRight = msg.ReadBoolean(); facingRight = msg.ReadBoolean();
} }
Vector2 pos = new Vector2(msg.ReadFloat(), msg.ReadFloat()); Vector2 pos = new Vector2(
msg.ReadFloat(),
msg.ReadFloat());
var posInfo = var posInfo = new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, networkUpdateID, sendingTime);
GameMain.NetworkMember.Character == this ?
new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, networkUpdateID) :
new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, sendingTime);
int index = 0; int index = 0;
if (GameMain.NetworkMember.Character == this) if (GameMain.NetworkMember.Character == this && AllowMovement)
{ {
while (index < memPos.Count && posInfo.ID > memPos[index].ID) while (index < memPos.Count && posInfo.ID > memPos[index].ID)
{
index++; index++;
}
} }
else else
{ {
while (index < memPos.Count && posInfo.Timestamp > memPos[index].Timestamp) while (index < memPos.Count && posInfo.Timestamp > memPos[index].Timestamp)
{
index++; index++;
}
} }
memPos.Insert(index, posInfo); memPos.Insert(index, posInfo);
@@ -2192,7 +2188,7 @@ namespace Barotrauma
return; return;
} }
Health = msg.ReadRangedSingle(minHealth, maxHealth, 8); health = msg.ReadRangedSingle(minHealth, maxHealth, 8);
bool lowOxygen = msg.ReadBoolean(); bool lowOxygen = msg.ReadBoolean();
if (lowOxygen) if (lowOxygen)
@@ -269,6 +269,11 @@ namespace Barotrauma
private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character) private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character)
{ {
if (GameMain.DebugDraw)
{
GUI.DrawString(spriteBatch, new Vector2(30, GameMain.GraphicsHeight - 260), "Stun: "+character.Stun, Color.White);
}
if (drowningBar == null) if (drowningBar == null)
{ {
int width = 100, height = 20; int width = 100, height = 20;
+7 -6
View File
@@ -20,21 +20,22 @@ namespace Barotrauma
public readonly UInt32 ID; public readonly UInt32 ID;
public PosInfo(Vector2 pos, Direction dir, float time) public PosInfo(Vector2 pos, Direction dir, float time)
: this(pos, dir, 0, time)
{ {
Position = pos;
Direction = dir;
Timestamp = time;
ID = 0;
} }
public PosInfo(Vector2 pos, Direction dir, UInt32 ID) public PosInfo(Vector2 pos, Direction dir, UInt32 ID)
: this(pos, dir, ID, 0.0f)
{
}
public PosInfo(Vector2 pos, Direction dir, UInt32 ID, float time)
{ {
Position = pos; Position = pos;
Direction = dir; Direction = dir;
this.ID = ID; this.ID = ID;
Timestamp = 0.0f; Timestamp = time;
} }
} }