(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
@@ -13,39 +13,13 @@ namespace Barotrauma
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
if (soundRange > 0.0f)
{
Color color;
if (Entity is Character)
{
color = Color.Yellow;
}
else if (Entity is Item)
{
color = Color.Orange;
}
else
{
color = Color.OrangeRed;
}
Color color = Entity is Character ? Color.Yellow : Color.Orange;
ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
ShapeExtensions.DrawCircle(spriteBatch, pos, 3, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
}
if (sightRange > 0.0f)
{
Color color;
if (Entity is Character)
{
color = Color.CornflowerBlue;
}
else if (Entity is Item)
{
color = Color.CadetBlue;
}
else
{
color = Color.WhiteSmoke;
}
Color color = Entity is Character ? Color.CornflowerBlue : Color.CadetBlue;
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
ShapeExtensions.DrawCircle(spriteBatch, pos, 6, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
}
}
}
@@ -16,17 +16,18 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null)
{
GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.5f, 0, 4);
GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5);
if (wallTarget != null)
{
Vector2 wallTargetPos = wallTarget.Position;
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
wallTargetPos.Y = -wallTargetPos.Y;
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false);
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.FormatZeroDecimal()})", Color.Red, Color.Black);
GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red);
}
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
@@ -51,15 +52,24 @@ namespace Barotrauma
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
if (LatchOntoAI != null)
if (latchOntoAI != null)
{
foreach (Joint attachJoint in LatchOntoAI.AttachJoints)
foreach (Joint attachJoint in latchOntoAI.AttachJoints)
{
GUI.DrawLine(spriteBatch,
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Green, 0, 4);
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Orange * 0.6f, 0, 5);
}
if (latchOntoAI.WallAttachPos.HasValue)
{
GUI.DrawLine(spriteBatch, pos,
ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Orange * 0.6f, 0, 3);
}
}
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
if (LatchOntoAI.WallAttachPos.HasValue)
{
GUI.DrawLine(spriteBatch, pos,
@@ -67,34 +77,22 @@ namespace Barotrauma
}
}
if (steeringManager is IndoorsSteeringManager pathSteering)
GUI.DrawLine(spriteBatch,
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
Color.Orange * 0.6f, 0, 3);
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
{
var path = pathSteering.CurrentPath;
if (path != null)
{
if (path.CurrentNode != null)
{
GUI.DrawLine(spriteBatch, pos,
new Vector2(path.CurrentNode.DrawPosition.X, -path.CurrentNode.DrawPosition.Y),
Color.DarkViolet, 0, 3);
GUI.DrawLine(spriteBatch,
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
Color.Orange * 0.6f, 0, 3);
GUI.DrawString(spriteBatch, pos - new Vector2(0, 100), "Path cost: " + path.Cost.FormatZeroDecimal(), Color.White, Color.Black * 0.5f);
}
for (int i = 1; i < path.Nodes.Count; i++)
{
var previousNode = path.Nodes[i - 1];
var currentNode = path.Nodes[i];
GUI.DrawLine(spriteBatch,
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
Color.Red * 0.5f, 0, 3);
GUI.SmallFont.DrawString(spriteBatch,
currentNode.ID.ToString(),
new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
Color.Red);
}
}
GUI.SmallFont.DrawString(spriteBatch,
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
Color.LightGreen);
}
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
@@ -75,12 +75,11 @@ namespace Barotrauma
GUI.SmallFont.DrawString(spriteBatch,
currentNode.ID.ToString(),
new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
Color.SkyBlue);
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y - 10),
Color.LightGreen);
}
}
}
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
//if (Character.IsKeyDown(InputType.Aim))
@@ -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();
@@ -224,20 +224,6 @@ namespace Barotrauma
}
}
if (SelectedConstruction != null && SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)))
{
if (GameMain.Client != null)
{
//emulate a Select input to get the character to deselect the item server-side
keys[(int)InputType.Select].Hit = true;
}
//reset focus to prevent us from accidentally interacting with another entity
focusedItem = null;
focusedCharacter = null;
findFocusedTimer = 0.2f;
SelectedConstruction = null;
}
DoInteractionUpdate(deltaTime, mouseSimPos);
}
@@ -341,8 +327,6 @@ namespace Barotrauma
debugInteractablesAtCursor.Clear();
debugInteractablesNearCursor.Clear();
bool draggingItemToWorld = CharacterInventory.DraggingItemToWorld;
//reduce the amount of aim assist if an item has been selected
//= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item
//otherwise it would be too easy to accidentally switch the selected item when rewiring items
@@ -364,15 +348,6 @@ namespace Barotrauma
if (item.body != null && !item.body.Enabled) continue;
if (item.ParentInventory != null) continue;
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
if (draggingItemToWorld)
{
if (item.OwnInventory == null ||
!item.OwnInventory.CanBePut(CharacterInventory.draggingItem))
{
continue;
}
}
float distanceToItem = float.PositiveInfinity;
if (item.IsInsideTrigger(displayPosition, out Rectangle transformedTrigger))
@@ -248,7 +248,7 @@ namespace Barotrauma
scale: scale);
}
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
if (!GUI.DisableItemHighlights)
{
var hudTexts = focusedItem.GetHUDTexts(character);
@@ -241,12 +241,10 @@ namespace Barotrauma
if (!string.IsNullOrEmpty(jobIdentifier))
{
jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier);
byte skillCount = inc.ReadByte();
for (int i = 0; i < skillCount; i++)
for (int i = 0; i < jobPrefab.Skills.Count; i++)
{
string skillIdentifier = inc.ReadString();
float skillLevel = inc.ReadSingle();
skillLevels.Add(skillIdentifier, skillLevel);
skillLevels.Add(jobPrefab.Skills[i].Identifier, skillLevel);
}
}
@@ -256,6 +254,7 @@ namespace Barotrauma
ID = infoID,
};
ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count);
if (ch.Job != null)
{
foreach (KeyValuePair<string, float> skill in skillLevels)
@@ -263,12 +262,11 @@ namespace Barotrauma
Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key);
if (matchingSkill == null)
{
ch.Job.Skills.Add(new Skill(skill.Key, skill.Value));
DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\"");
continue;
}
matchingSkill.Level = skill.Value;
}
ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier));
}
return ch;
}
@@ -3,6 +3,7 @@ using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
namespace Barotrauma
{
@@ -68,14 +68,6 @@ namespace Barotrauma
private float dropItemAnimDuration = 0.5f;
private float dropItemAnimTimer;
public Item DroppedItem
{
get
{
return droppedItem;
}
}
private Item droppedItem;
private GUIComponent draggingMed;
@@ -108,15 +100,13 @@ namespace Barotrauma
if (openHealthWindow == value) return;
if (value != null && !value.UseHealthWindow) return;
var prevOpenHealthWindow = openHealthWindow;
openHealthWindow = value;
toggledThisFrame = true;
if (Character.Controlled == null) { return; }
if (value == null &&
Character.Controlled?.SelectedCharacter?.CharacterHealth != null &&
Character.Controlled.SelectedCharacter.CharacterHealth == prevOpenHealthWindow &&
Character.Controlled.SelectedCharacter.CharacterHealth == openHealthWindow &&
!Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
{
Character.Controlled.DeselectCharacter();
@@ -547,13 +537,11 @@ namespace Barotrauma
}
if (PlayerInput.KeyHit(InputType.Health) && GUI.KeyboardDispatcher.Subscriber == null &&
Character.Controlled.AllowInput && !toggledThisFrame)
Character.AllowInput && Character.FocusedCharacter == null && !toggledThisFrame)
{
if (openHealthWindow != null)
{
OpenHealthWindow = null;
}
else if (Character.Controlled == Character && Character.Controlled.FocusedCharacter == null)
else
{
OpenHealthWindow = this;
forceAfflictionContainerUpdate = true;
@@ -566,10 +554,7 @@ namespace Barotrauma
HUD.CloseHUD(HUDLayoutSettings.HealthWindowAreaLeft))
{
//emulate a Health input to get the character to deselect the item server-side
if (GameMain.Client != null)
{
Character.Controlled.Keys[(int)InputType.Health].Hit = true;
}
Character.Keys[(int)InputType.Health].Hit = true;
OpenHealthWindow = null;
}
}