From ae6b797d7313563fb779911615c6bd189da531f5 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 1 Apr 2019 22:49:58 +0300 Subject: [PATCH] (c2e1b24e2) Fixed remote characters sliding slowly to the left in multiplayer. Happened because linear velocity was written with an accuracy of 12 bits, causing the lowest possible value to be about 1.5 cm/s. Now extremely low velocity values are rounded down to zero. The server also now quantizes the LinearVelocity/AngularVelocity values, which should make position syncing a little more reliable because the server runs the physics using the same rounded values as the clients. --- .../Source/Characters/Animation/Ragdoll.cs | 15 ++++-- .../Source/Characters/CharacterNetworking.cs | 2 + Barotrauma/BarotraumaClient/Source/GUI/GUI.cs | 7 +++ .../Source/Physics/PhysicsBody.cs | 3 ++ .../Source/Characters/CharacterNetworking.cs | 6 ++- .../Source/Physics/PhysicsBody.cs | 14 +++-- .../Source/Characters/AI/EnemyAIController.cs | 52 ++++++++++++++----- .../Source/Items/ItemPrefab.cs | 33 ++++++++++++ .../Source/Networking/NetConfig.cs | 18 +++++++ 9 files changed, 122 insertions(+), 28 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index c6f95eda7..c2761aeaf 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -88,13 +88,13 @@ namespace Barotrauma Collider.AngularVelocity = newAngularVelocity; float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition); - float errorTolerance = character.AllowInput ? 0.01f : 0.1f; + float errorTolerance = character.AllowInput ? 0.01f : 0.2f; if (distSqrd > errorTolerance) { if (distSqrd > 10.0f || !character.AllowInput) { Collider.TargetRotation = newRotation; - SetPosition(newPosition, lerp: distSqrd < 1.0f); + SetPosition(newPosition, lerp: distSqrd < 5.0f); } else { @@ -108,8 +108,15 @@ namespace Barotrauma // -> we need to correct it manually if (!character.AllowInput) { - MainLimb.PullJointWorldAnchorB = Collider.SimPosition; - MainLimb.PullJointEnabled = true; + float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition); + float mainLimbErrorTolerance = 0.1f; + //if the main limb is roughly at the correct position and the collider isn't moving (much at least), + //don't attempt to correct the position. + if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f) + { + MainLimb.PullJointWorldAnchorB = Collider.SimPosition; + MainLimb.PullJointEnabled = true; + } } } character.MemLocalState.Clear(); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs index 5753c1c97..90d2622fd 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -211,6 +211,7 @@ namespace Barotrauma Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); + linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float? rotation = null; @@ -220,6 +221,7 @@ namespace Barotrauma rotation = msg.ReadFloat(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); + angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index ec5b88851..cbb751f50 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -656,6 +656,13 @@ namespace Barotrauma msg.Timer -= deltaTime; msg.Pos += msg.Velocity * deltaTime; } + + foreach (GUIMessage msg in messages) + { + if (!msg.WorldSpace) continue; + msg.Timer -= deltaTime; + msg.Pos += msg.Velocity * deltaTime; + } } messages.RemoveAll(m => m.Timer <= 0.0f); diff --git a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs index f231c83a0..88e1011e8 100644 --- a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs @@ -171,9 +171,12 @@ namespace Barotrauma newVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); + newVelocity = NetConfig.Quantize(newVelocity, -MaxVel, MaxVel, 12); + if (!fixedRotation) { newAngularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); + newAngularVelocity = NetConfig.Quantize(newAngularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } } msg.ReadPadBits(); diff --git a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs index d9831f872..8b4d121dc 100644 --- a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs @@ -376,8 +376,9 @@ namespace Barotrauma tempBuffer.Write(SimPosition.X); tempBuffer.Write(SimPosition.Y); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; - tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); - tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); + AnimController.Collider.LinearVelocity = NetConfig.Quantize(AnimController.Collider.LinearVelocity, -MaxVel, MaxVel, 12); + tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel, 12); + tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12); bool fixedRotation = AnimController.Collider.FarseerBody.FixedRotation; tempBuffer.Write(fixedRotation); @@ -385,6 +386,7 @@ namespace Barotrauma { tempBuffer.Write(AnimController.Collider.Rotation); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; + AnimController.Collider.AngularVelocity = NetConfig.Quantize(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8); } diff --git a/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs index b2276c7f5..10580b11e 100644 --- a/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Barotrauma.Networking; +using Barotrauma.Networking; using Lidgren.Network; using Microsoft.Xna.Framework; +using System; namespace Barotrauma { @@ -37,10 +33,12 @@ namespace Barotrauma if (FarseerBody.Awake) { body.Enabled = true; - msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); - msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); + body.LinearVelocity = NetConfig.Quantize(body.LinearVelocity, -MaxVel, MaxVel, 12); + msg.WriteRangedSingle(body.LinearVelocity.X, -MaxVel, MaxVel, 12); + msg.WriteRangedSingle(body.LinearVelocity.Y, -MaxVel, MaxVel, 12); if (!FarseerBody.FixedRotation) { + body.AngularVelocity = NetConfig.Quantize(body.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); msg.WriteRangedSingle(MathHelper.Clamp(body.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8); } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 24b7e331e..983c2091b 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -726,8 +726,7 @@ namespace Barotrauma if (!canAttack && !IsCoolDownRunning) { // If not, reset the attacking limb, if the cooldown is not running - // Don't use the property, because we don't want cancel reversing, if we are reversing. - _attackingLimb = null; + AttackingLimb = null; } } @@ -798,6 +797,7 @@ namespace Barotrauma { UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance); } + return false; } private bool SteerThroughGap(Structure wall, WallSection section, Vector2 targetWorldPos, float deltaTime) @@ -1169,15 +1169,15 @@ namespace Barotrauma else if (target.Entity is Structure s) { targetingTag = "wall"; - if (!s.HasBody) - { - // Ignore structures that doesn't have a body (not walls) - continue; - } - // Ignore walls when inside. - valueModifier = character.CurrentHull == null ? 1 : 0; if (aggressiveBoarding) { + // Ignore walls when inside. + valueModifier = character.CurrentHull == null ? 2 : 0; + if (valueModifier > 0) + { + // Ignore structures that doesn't have a body (not walls) + valueModifier *= s.HasBody ? 1 : 0; + } for (int i = 0; i < s.Sections.Length; i++) { var section = s.Sections[i]; @@ -1194,17 +1194,37 @@ namespace Barotrauma } } } + } + else + { + targetingTag = "room"; + } + if (door != null) + { + // If there's not a more specific tag for the door + if (string.IsNullOrEmpty(targetingTag) || targetingTag == "room") + { + targetingTag = "door"; + } + bool isOutdoor = door.LinkedGap?.FlowTargetHull != null && !door.LinkedGap.IsRoomToRoom; + bool isOpen = door.IsOpen || door.Item.Condition <= 0.0f; + //increase priority if the character is outside and an aggressive boarder, and the door is from outside to inside + if (aggressiveBoarding) + { + if (character.CurrentHull == null) + { + valueModifier = isOutdoor ? 1 : 0; + valueModifier *= isOpen ? 5 : 1; + } + } else { // Ignore disabled walls bool isDisabled = true; for (int i = 0; i < s.Sections.Length; i++) { - if (!s.SectionBodyDisabled(i)) - { - isDisabled = false; - break; - } + valueModifier = isOutdoor ? 0 : 1; + valueModifier *= isOpen ? 0 : 1; } if (isDisabled) { @@ -1243,6 +1263,10 @@ namespace Barotrauma { continue; } + else if (isOpen) //ignore broken and open doors + { + continue; + } } else if (target.Entity is IDamageable targetDamageable && targetDamageable.Health <= 0.0f) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs index c298546ab..76cf20ef1 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs @@ -917,6 +917,39 @@ namespace Barotrauma AllowedLinks = element.GetAttributeStringArray("allowedlinks", new string[0], convertToLowerInvariant: true).ToList(); + if (sprite == null) + { + DebugConsole.ThrowError("Item \"" + Name + "\" has no sprite!"); +#if SERVER + sprite = new Sprite("", Vector2.Zero); + sprite.SourceRect = new Rectangle(0, 0, 32, 32); +#else + sprite = new Sprite(TextureLoader.PlaceHolderTexture, null, null) + { + Origin = TextureLoader.PlaceHolderTexture.Bounds.Size.ToVector2() / 2 + }; +#endif + size = sprite.size; + sprite.EntityID = identifier; + } + + if (!category.HasFlag(MapEntityCategory.Legacy) && string.IsNullOrEmpty(identifier)) + { + DebugConsole.ThrowError( + "Item prefab \"" + name + "\" has no identifier. All item prefabs have a unique identifier string that's used to differentiate between items during saving and loading."); + } + if (!string.IsNullOrEmpty(identifier)) + { + MapEntityPrefab existingPrefab = List.Find(e => e.Identifier == identifier); + if (existingPrefab != null) + { + DebugConsole.ThrowError( + "Map entity prefabs \"" + name + "\" and \"" + existingPrefab.Name + "\" have the same identifier!"); + } + } + + AllowedLinks = element.GetAttributeStringArray("allowedlinks", new string[0], convertToLowerInvariant: true).ToList(); + List.Add(this); } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs index 74b6afcb2..5c7bfa0f0 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs @@ -74,5 +74,23 @@ namespace Barotrauma.Networking if (lengthSqr > 1000.0f) { return Vector2.Zero; } return cursorPositionError *= 0.7f; } + + public static Vector2 Quantize(Vector2 value, float min, float max, int numberOfBits) + { + return new Vector2( + Quantize(value.X, min, max, numberOfBits), + Quantize(value.Y, min, max, numberOfBits)); + } + + public static float Quantize(float value, float min, float max, int numberOfBits) + { + float step = (max - min) / (1 << (numberOfBits + 1)); + if (Math.Abs(value) < step + 0.00001f) + { + return 0.0f; + } + + return MathUtils.RoundTowardsClosest(MathHelper.Clamp(value, min, max), step); + } } }