From bb685019a28ac1c9cc9cb06f4116fbfe32a10d57 Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 3 Jan 2017 23:49:37 +0200 Subject: [PATCH] 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 --- .../Animation/HumanoidAnimController.cs | 8 +- .../Source/Characters/Animation/Ragdoll.cs | 35 +++++++-- Subsurface/Source/Characters/Character.cs | 78 +++++++++---------- Subsurface/Source/Characters/CharacterHUD.cs | 5 ++ Subsurface/Source/Physics/PhysicsBody.cs | 13 ++-- 5 files changed, 81 insertions(+), 58 deletions(-) diff --git a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs index 84a864c36..9fe45b871 100644 --- a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs @@ -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); } } diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs index efeedf679..1d2f41f3a 100644 --- a/Subsurface/Source/Characters/Animation/Ragdoll.cs +++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs @@ -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); diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 3eb147425..6e82a9d2d 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -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) diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index aa5c11ef8..8f81e6214 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -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; diff --git a/Subsurface/Source/Physics/PhysicsBody.cs b/Subsurface/Source/Physics/PhysicsBody.cs index 037a62454..79ff44613 100644 --- a/Subsurface/Source/Physics/PhysicsBody.cs +++ b/Subsurface/Source/Physics/PhysicsBody.cs @@ -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; } }