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

View File

@@ -59,7 +59,7 @@ namespace Barotrauma
ColliderIndex = Crouching ? 1 : 0;
if (!Crouching && ColliderIndex == 1) Crouching = true;
if (character.IsDead || character.IsUnconscious || stunTimer > 0.0f)
if (!character.AllowMovement)
{
levitatingCollider = false;
Collider.FarseerBody.FixedRotation = false;
@@ -921,13 +921,15 @@ namespace Barotrauma
target.AnimController.IgnorePlatforms = IgnorePlatforms;
if (target.Stun > 0.0f || target.IsUnconscious || target.IsDead)
if (!target.AllowMovement)
{
target.AnimController.TargetMovement = TargetMovement;
}
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);
}
}

View File

@@ -1170,12 +1170,20 @@ namespace Barotrauma
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
//(in case the ragdoll has gotten stuck somewhere)
if (Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition) > allowedDist*allowedDist)
float distSqrd = Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition);
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)
{
limb.body.CollidesWith = Physics.CollisionNone;
@@ -1197,20 +1205,31 @@ namespace Barotrauma
{
if (GameMain.NetworkMember == null) return;
if (character != GameMain.NetworkMember.Character ||
character.IsUnconscious || character.Stun > 0.0f)
if (character != GameMain.NetworkMember.Character || !character.AllowMovement)
{
//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)
{
Collider.LinearVelocity = Vector2.Zero;
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
{
if (character.MemPos.Count < 1) return;
overrideTargetMovement = Vector2.Zero;
PosInfo serverPos = character.MemPos.Last();
int localPosIndex = character.MemLocalPos.FindIndex(m => m.ID == serverPos.ID);

View File

@@ -211,6 +211,11 @@ namespace Barotrauma
}
}
public bool AllowMovement
{
get { return !IsUnconscious && Stun <= 0.0f && !isDead; }
}
public Vector2 CursorPosition
{
get { return cursorPosition; }
@@ -1302,7 +1307,7 @@ namespace Barotrauma
if (this != Character.Controlled)
{
if (GameMain.Server != null && !(this is AICharacter))
if (GameMain.Server != null && !(this is AICharacter) && AllowMovement)
{
if (memInput.Count > 0)
{
@@ -1333,42 +1338,38 @@ namespace Barotrauma
{
isStillCountdown = 15;
}
//DebugConsole.NewMessage(Convert.ToString(memInput.Count), Color.Lime);
}
else
{
AnimController.Frozen = true;
if (AllowMovement) AnimController.Frozen = true;
return;
}
}
}
else
else if (GameMain.Client != null)
{
if (GameMain.Client != null)
{
memLocalPos.Add(new PosInfo(SimPosition, AnimController.TargetDir, LastNetworkUpdateID));
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;
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;
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);
}
}
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);
}
}
if (networkUpdateSent)
@@ -2113,27 +2114,22 @@ namespace Barotrauma
facingRight = msg.ReadBoolean();
}
Vector2 pos = new Vector2(msg.ReadFloat(), msg.ReadFloat());
Vector2 pos = new Vector2(
msg.ReadFloat(),
msg.ReadFloat());
var posInfo =
GameMain.NetworkMember.Character == this ?
new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, networkUpdateID) :
new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, sendingTime);
var posInfo = new PosInfo(pos, facingRight ? Direction.Right : Direction.Left, networkUpdateID, sendingTime);
int index = 0;
if (GameMain.NetworkMember.Character == this)
if (GameMain.NetworkMember.Character == this && AllowMovement)
{
while (index < memPos.Count && posInfo.ID > memPos[index].ID)
{
index++;
}
while (index < memPos.Count && posInfo.ID > memPos[index].ID)
index++;
}
else
{
while (index < memPos.Count && posInfo.Timestamp > memPos[index].Timestamp)
{
index++;
}
while (index < memPos.Count && posInfo.Timestamp > memPos[index].Timestamp)
index++;
}
memPos.Insert(index, posInfo);
@@ -2192,7 +2188,7 @@ namespace Barotrauma
return;
}
Health = msg.ReadRangedSingle(minHealth, maxHealth, 8);
health = msg.ReadRangedSingle(minHealth, maxHealth, 8);
bool lowOxygen = msg.ReadBoolean();
if (lowOxygen)

View File

@@ -269,6 +269,11 @@ namespace Barotrauma
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)
{
int width = 100, height = 20;

View File

@@ -20,21 +20,22 @@ namespace Barotrauma
public readonly UInt32 ID;
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)
: this(pos, dir, ID, 0.0f)
{
}
public PosInfo(Vector2 pos, Direction dir, UInt32 ID, float time)
{
Position = pos;
Direction = dir;
this.ID = ID;
Timestamp = 0.0f;
Timestamp = time;
}
}