Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -64,6 +64,9 @@ namespace Barotrauma
}
}
private readonly List<Body> limbBodies = new List<Body>();
public IEnumerable<Body> LimbBodies => limbBodies;
public bool HasMultipleLimbsOfSameType => limbs != null && limbs.Length > limbDictionary.Count;
private bool frozen;
@@ -91,7 +94,7 @@ namespace Barotrauma
private bool simplePhysicsEnabled;
public Character Character => character;
protected Character character;
protected readonly Character character;
protected float strongestImpact;
@@ -108,7 +111,7 @@ namespace Barotrauma
//a movement vector that overrides targetmovement if trying to steer
//a Character to the position sent by server in multiplayer mode
protected Vector2 overrideTargetMovement;
protected Vector2? overrideTargetMovement;
protected float floorY, standOnFloorY;
protected Fixture floorFixture;
@@ -138,6 +141,12 @@ namespace Barotrauma
private Category prevCollisionCategory = Category.None;
/// <summary>
/// When the character is alive/conscious, the collider drives the character's movement and is used to sync the character's position in MP.
/// When unconscious, the ragdoll controls the movement and the collider just sticks to the main limb.
/// </summary>
public bool ColliderControlsMovement => character.CanMove;
public bool IsStuck => Limbs.Any(l => l.IsStuck);
public PhysicsBody Collider
@@ -185,7 +194,7 @@ namespace Barotrauma
Vector2 pos = collider[colliderIndex].SimPosition;
pos.Y -= collider[colliderIndex].Height * 0.5f;
pos.Y += collider[value].Height * 0.5f;
collider[value].SetTransform(pos, collider[colliderIndex].Rotation);
collider[value].SetTransformIgnoreContacts(pos, collider[colliderIndex].Rotation);
collider[value].LinearVelocity = collider[colliderIndex].LinearVelocity;
collider[value].AngularVelocity = collider[colliderIndex].AngularVelocity;
@@ -282,7 +291,7 @@ namespace Barotrauma
foreach (Limb limb in Limbs)
{
if (limb.IsSevered || !limb.body.PhysEnabled) { continue; }
limb.body.SetTransform(Collider.SimPosition, Collider.Rotation);
limb.body.SetTransformIgnoreContacts(Collider.SimPosition, Collider.Rotation);
//reset pull joints (they may be somewhere far away if the character has moved from the position where animations were last updated)
limb.PullJointEnabled = false;
limb.PullJointWorldAnchorB = limb.SimPosition;
@@ -297,11 +306,11 @@ namespace Barotrauma
{
get
{
return (overrideTargetMovement == Vector2.Zero) ? targetMovement : overrideTargetMovement;
return overrideTargetMovement ?? targetMovement;
}
set
{
if (!MathUtils.IsValid(value)) return;
if (!MathUtils.IsValid(value)) { return; }
targetMovement.X = MathHelper.Clamp(value.X, -MAX_SPEED, MAX_SPEED);
targetMovement.Y = MathHelper.Clamp(value.Y, -MAX_SPEED, MAX_SPEED);
}
@@ -385,15 +394,16 @@ namespace Barotrauma
if (ragdollParams != null)
{
RagdollParams = ragdollParams;
if (!character.VariantOf.IsEmpty)
{
RagdollParams.TryApplyVariantScale(character.Params.VariantFile);
}
}
else
{
// Only re-equip items if the ragdoll doesn't change, because re-equiping items might throw exceptions if the limbs have changed.
items = limbs?.ToDictionary(l => l.Params, l => l.WearingItems);
}
if (character.Params.VariantFile is XDocument variantFile)
{
RagdollParams.TryApplyVariantScale(variantFile);
}
foreach (var limbParams in RagdollParams.Limbs)
{
if (!PhysicsBody.IsValidShape(limbParams.Radius, limbParams.Height, limbParams.Width))
@@ -430,18 +440,13 @@ namespace Barotrauma
if (character.IsHusk && character.Params.UseHuskAppendage)
{
bool inEditor = false;
#if CLIENT
inEditor = Screen.Selected == GameMain.CharacterEditorScreen;
#endif
var characterPrefab = CharacterPrefab.FindByFilePath(character.ConfigPath);
if (characterPrefab?.ConfigElement != null)
{
var mainElement = characterPrefab.ConfigElement;
foreach (var huskAppendage in mainElement.GetChildElements("huskappendage"))
{
if (!inEditor && huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
if (huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
Identifier afflictionIdentifier = huskAppendage.GetAttributeIdentifier("affliction", Identifier.Empty);
if (!AfflictionPrefab.Prefabs.TryGet(afflictionIdentifier, out AfflictionPrefab affliction) ||
@@ -452,7 +457,7 @@ namespace Barotrauma
}
else
{
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskAppendage, ragdoll: this);
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskedSpeciesName: character.SpeciesName, huskAppendage, ragdoll: this);
}
}
}
@@ -478,7 +483,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Invalid collider dimensions: " + cParams.Name);
break; ;
}
var body = new PhysicsBody(cParams);
var body = new PhysicsBody(cParams, findNewContacts: false);
collider.Add(body);
body.UserData = character;
body.FarseerBody.OnCollision += OnLimbCollision;
@@ -520,7 +525,7 @@ namespace Barotrauma
{
if (joint == null) { continue; }
float angle = (joint.LowerLimit + joint.UpperLimit) / 2.0f;
joint.LimbB?.body?.SetTransform(
joint.LimbB?.body?.SetTransformIgnoreContacts(
(joint.WorldAnchorA - MathUtils.RotatePointAroundTarget(joint.LocalAnchorB, Vector2.Zero, joint.BodyA.Rotation + angle, true)),
joint.BodyA.Rotation + angle);
}
@@ -528,11 +533,13 @@ namespace Barotrauma
protected void CreateLimbs()
{
limbBodies.Clear();
limbs?.ForEach(l => l.Remove());
Mass = 0;
DebugConsole.Log($"Creating limbs from {RagdollParams.Name}.");
limbDictionary = new Dictionary<LimbType, Limb>();
limbs = new Limb[RagdollParams.Limbs.Count];
RagdollParams.Limbs.ForEach(l => AddLimb(l));
RagdollParams.Limbs.ForEach(AddLimb);
if (limbs.Contains(null)) { return; }
SetupDrawOrder();
}
@@ -549,11 +556,11 @@ namespace Barotrauma
/// <summary>
/// Resets the serializable data to the currently selected ragdoll params.
/// Force reloading always loads the xml stored on the disk.
/// Always loads the xml stored on the disk.
/// </summary>
public void ResetRagdoll(bool forceReload = false)
public void ResetRagdoll()
{
RagdollParams.Reset(forceReload);
RagdollParams.Reset(forceReload: true);
ResetJoints();
ResetLimbs();
}
@@ -577,7 +584,7 @@ namespace Barotrauma
public void AddJoint(JointParams jointParams)
{
if (!checkLimbIndex(jointParams.Limb2, "Limb1") || !checkLimbIndex(jointParams.Limb2, "Limb2"))
if (!checkLimbIndex(jointParams.Limb1, "Limb1") || !checkLimbIndex(jointParams.Limb2, "Limb2"))
{
return;
}
@@ -621,6 +628,7 @@ namespace Barotrauma
{
throw new Exception($"Failed to add a limb to the character \"{Character?.ConfigPath ?? "null"}\" (limb index {ID} out of bounds). The ragdoll file may be configured incorrectly.");
}
limbBodies.Add(limb.body.FarseerBody);
Limbs[ID] = limb;
Mass += limb.Mass;
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
@@ -632,6 +640,7 @@ namespace Barotrauma
limb.body.FarseerBody.OnCollision += OnLimbCollision;
Array.Resize(ref limbs, Limbs.Length + 1);
Limbs[Limbs.Length - 1] = limb;
limbBodies.Add(limb.body.FarseerBody);
Mass += limb.Mass;
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
SetupDrawOrder();
@@ -639,14 +648,14 @@ namespace Barotrauma
public void RemoveLimb(Limb limb)
{
if (!Limbs.Contains(limb)) return;
if (!Limbs.Contains(limb)) { return; }
Limb[] newLimbs = new Limb[Limbs.Length - 1];
int i = 0;
foreach (Limb existingLimb in Limbs)
{
if (existingLimb == limb) continue;
if (existingLimb == limb) { continue; }
newLimbs[i] = existingLimb;
i++;
}
@@ -684,8 +693,10 @@ namespace Barotrauma
LimbJoints = newJoints;
}
SubtractMass(limb);
limbBodies.Remove(limb.body.FarseerBody);
limb.Remove();
System.Diagnostics.Debug.Assert(!limbs.Contains(limb));
System.Diagnostics.Debug.Assert(limbs.None(l => l.Removed));
foreach (LimbJoint limbJoint in attachedJoints)
{
GameMain.World.Remove(limbJoint.Joint);
@@ -819,9 +830,10 @@ namespace Barotrauma
{
if (character.DisableImpactDamageTimer > 0.0f) { return; }
if (f2.Body?.UserData is Item)
if (f2.Body?.UserData is Item &&
f2.Body.BodyType != BodyType.Static)
{
//no impact damage from items
//no impact damage from items with a non-static body
//items that can impact characters (melee weapons, projectiles) should handle the damage themselves
return;
}
@@ -1073,7 +1085,7 @@ namespace Barotrauma
Vector2 moveDir = hullDiff.LengthSquared() < 0.001f ? Vector2.UnitY : Vector2.Normalize(hullDiff);
//find a position 32 units away from the hull
if (MathUtils.GetLineRectangleIntersection(
if (MathUtils.GetLineWorldRectangleIntersection(
newHull.WorldPosition,
newHull.WorldPosition + moveDir * Math.Max(newHull.Rect.Width, newHull.Rect.Height),
new Rectangle(newHull.WorldRect.X - 32, newHull.WorldRect.Y + 32, newHull.WorldRect.Width + 64, newHull.Rect.Height + 64),
@@ -1294,6 +1306,11 @@ namespace Barotrauma
}
}
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
Collider.LinearVelocity = new Vector2(
NetConfig.Quantize(Collider.LinearVelocity.X, -MaxVel, MaxVel, 12),
NetConfig.Quantize(Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12));
if (forceStanding)
{
inWater = false;
@@ -1400,7 +1417,12 @@ namespace Barotrauma
limb.Update(deltaTime);
}
if (!inWater && character.AllowInput && levitatingCollider)
bool isAttachedToController =
character.SelectedItem?.GetComponent<Items.Components.Controller>() is { } controller &&
controller.User == character &&
controller.IsAttachedUser(controller.User);
if (!inWater && character.AllowInput && levitatingCollider && !isAttachedToController)
{
if (onGround && Collider.LinearVelocity.Y > -ImpactTolerance)
{
@@ -1433,7 +1455,7 @@ namespace Barotrauma
else
{
// Falling -> ragdoll briefly if we are not moving at all, because we are probably stuck.
if (Collider.LinearVelocity == Vector2.Zero)
if (Collider.LinearVelocity == Vector2.Zero && !character.IsRemotePlayer)
{
character.IsRagdolled = true;
if (character.IsBot)
@@ -1448,6 +1470,30 @@ namespace Barotrauma
forceNotStanding = false;
}
/// <summary>
/// Update the logic that needs to run when the ragdoll is what controls the character's movement instead of the collider <see cref="ColliderControlsMovement"/>
/// (making the collider stick to the ragdoll's main limb).
/// </summary>
protected void UpdateRagdollControlsMovement()
{
levitatingCollider = false;
Collider.FarseerBody.FixedRotation = false;
if (Collider.Enabled)
{
//deactivating the collider -> make the main limb inherit the collider's velocity because it'll control the movement now
MainLimb.body.LinearVelocity = Collider.LinearVelocity;
Collider.Enabled = false;
}
Collider.LinearVelocity = MainLimb.LinearVelocity;
Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
//reset pull joints to prevent the character from "hanging" mid-air if pull joints had been active when the character was still moving
//(except when dragging, then we need the pull joints)
if (!Draggable || character.SelectedBy == null)
{
ResetPullJoints();
}
}
private void CheckBodyInRest(float deltaTime)
{
if (SimplePhysicsEnabled) { return; }
@@ -1910,7 +1956,7 @@ namespace Barotrauma
}
else
{
Collider.SetTransform(simPosition, Collider.Rotation);
Collider.SetTransformIgnoreContacts(simPosition, Collider.Rotation);
}
if (!MathUtils.NearlyEqual(limbMoveAmount, Vector2.Zero))
@@ -2009,7 +2055,7 @@ namespace Barotrauma
}
else
{
limb.body.SetTransform(movePos, rotation);
limb.body.SetTransformIgnoreContacts(movePos, rotation);
limb.PullJointWorldAnchorB = limb.PullJointWorldAnchorA;
limb.PullJointEnabled = false;
}
@@ -2084,7 +2130,7 @@ namespace Barotrauma
partial void UpdateNetPlayerPositionProjSpecific(float deltaTime, float lowestSubPos);
private void UpdateNetPlayerPosition(float deltaTime)
{
if (GameMain.NetworkMember == null) return;
if (GameMain.NetworkMember == null) { return; }
float lowestSubPos = float.MaxValue;
if (Submarine.Loaded.Any())
@@ -2113,26 +2159,48 @@ namespace Barotrauma
/// <summary>
/// Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
/// </summary>
public Limb GetLimb(LimbType limbType, bool excludeSevered = true)
/// <param name="limbType"></param>
/// <param name="excludeSevered">Should we filter out severed limbs?</param>
/// <param name="useSecondaryType">Should we target limbs with secondary type instead of (primary) type?</param>
/// <param name="excludeLimbsWithSecondaryType">Should we filter out all limbs with a secondary type something else than "None"?</param>
/// <returns></returns>
public Limb GetLimb(LimbType limbType, bool excludeSevered = true, bool excludeLimbsWithSecondaryType = false, bool useSecondaryType = false)
{
if (limbDictionary.TryGetValue(limbType, out Limb limb))
Limb limb = null;
if (!HasMultipleLimbsOfSameType && !useSecondaryType && !excludeLimbsWithSecondaryType)
{
if (excludeSevered && limb.IsSevered)
// Faster method, but doesn't work when there's multiple limbs of the same type or if we want to seek/exclude limbs with different conditions.
if (limbDictionary.TryGetValue(limbType, out limb))
{
limb = null;
}
if (limb.Removed)
{
limb = null;
}
if (excludeSevered && limb is { IsSevered: true } )
{
limb = null;
}
}
}
if (limb == null && HasMultipleLimbsOfSameType)
if (limb == null)
{
// Didn't find a (valid) limb of the matching type. If there's multiple limbs of the same type, check the other limbs.
// Didn't seek or find a (valid) limb of the matching type. If there's multiple limbs of the same type, check the other limbs.
foreach (var l in limbs)
{
if (l.type != limbType) { continue; }
if (!excludeSevered || !l.IsSevered)
if (l.Removed) { continue; }
if (useSecondaryType)
{
limb = l;
break;
if (l.Params.SecondaryType != limbType) { continue; }
}
else if (l.type != limbType)
{
continue;
}
if (excludeSevered && l.IsSevered) { continue; }
if (excludeLimbsWithSecondaryType && l.Params.SecondaryType != LimbType.None) { continue; }
// Found a valid and match
limb = l;
break;
}
}
return limb;
@@ -2220,6 +2288,7 @@ namespace Barotrauma
}
limbs = null;
}
limbBodies.Clear();
if (collider != null)
{