diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index bcf133b30..fa30d8a82 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -108,6 +108,61 @@ namespace Barotrauma } } + //unconscious/dead characters can't correct their position using AnimController movement + // -> we need to correct it manually + if (!character.AllowInput) + { + 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.SelectedConstruction = character.MemState[0].SelectedItem; + } + + if (character.MemState[0].Animation == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.CPR; + } + else if (character.AnimController.Anim == AnimController.Animation.CPR) + { + character.AnimController.Anim = AnimController.Animation.None; + } + + Vector2 newVelocity = Collider.LinearVelocity; + Vector2 newPosition = Collider.SimPosition; + float newRotation = Collider.Rotation; + float newAngularVelocity = Collider.AngularVelocity; + Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity); + + newVelocity = newVelocity.ClampLength(100.0f); + if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; } + overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero; + + Collider.LinearVelocity = newVelocity; + Collider.AngularVelocity = newAngularVelocity; + + float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition); + float errorTolerance = character.AllowInput ? 0.01f : 0.2f; + if (distSqrd > errorTolerance) + { + if (distSqrd > 10.0f || !character.AllowInput) + { + Collider.TargetRotation = newRotation; + SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false); + } + else + { + Collider.TargetRotation = newRotation; + Collider.TargetPosition = newPosition; + Collider.MoveToTargetPosition(true); + } + } + //unconscious/dead characters can't correct their position using AnimController movement // -> we need to correct it manually if (!character.AllowInput) @@ -151,32 +206,34 @@ namespace Barotrauma } } - - if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120); - character.MemState.Clear(); + character.MemLocalState.Clear(); } - } - - partial void ImpactProjSpecific(float impact, Body body) - { - float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f); - - if (body.UserData is Limb limb && character.Stun <= 0f) + else { - if (impact > 3.0f) { PlayImpactSound(limb); } - } - else if (body.UserData is Limb || body == Collider.FarseerBody) - { - if (!character.IsRemotePlayer && impact > ImpactTolerance) + //remove states with a timestamp (there may still timestamp-based states + //in the list if the controlled character switches from timestamp-based interpolation to ID-based) + character.MemState.RemoveAll(m => m.Timestamp > 0.0f); + + for (int i = 0; i < character.MemLocalState.Count; i++) { - SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider); + if (character.Submarine == null) + { + //transform in-sub coordinates to outside coordinates + if (character.MemLocalState[i].Position.Y > lowestSubPos) + { + character.MemLocalState[i].TransformInToOutside(); + } + } + else if (currentHull?.Submarine != null) + { + //transform outside coordinates to in-sub coordinates + if (character.MemLocalState[i].Position.Y < lowestSubPos) + { + character.MemLocalState[i].TransformOutToInside(currentHull.Submarine); + } + } + } - } - if (Character.Controlled == character) - { - GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f); - } - } if (character.MemState.Count < 1) return; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs index 9a729b108..94131a5b3 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs @@ -601,7 +601,7 @@ namespace Barotrauma.Steam { // TODO: If you create a new mod via the workshop interface and enable it, it will show the error msg, but still allows you to enable the content. - if (File.Exists(newContentPackagePath)) + if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath)) { errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable") .Replace("[itemname]", item.Title) @@ -613,7 +613,7 @@ namespace Barotrauma.Steam foreach (ContentFile contentFile in contentPackage.Files) { string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path); - if (File.Exists(sourceFile) && File.Exists(contentFile.Path)) + if (File.Exists(sourceFile) && File.Exists(contentFile.Path) && !CheckFileEquality(sourceFile, contentFile.Path)) { errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable") .Replace("[itemname]", item.Title) @@ -685,6 +685,22 @@ namespace Barotrauma.Steam return true; } + private static bool CheckFileEquality(string filePath1, string filePath2) + { + if (filePath1 == filePath2) + { + return true; + } + + using (FileStream fs1 = File.OpenRead(filePath1)) + using (FileStream fs2 = File.OpenRead(filePath2)) + { + Md5Hash hash1 = new Md5Hash(fs1); + Md5Hash hash2 = new Md5Hash(fs2); + return hash1.Hash == hash2.Hash; + } + } + /// /// Disables a workshop item by removing the files from the game folder. /// diff --git a/Barotrauma/BarotraumaServer/Source/GameMain.cs b/Barotrauma/BarotraumaServer/Source/GameMain.cs index ebf4486e2..ec81b52c3 100644 --- a/Barotrauma/BarotraumaServer/Source/GameMain.cs +++ b/Barotrauma/BarotraumaServer/Source/GameMain.cs @@ -162,6 +162,23 @@ namespace Barotrauma } } + /// + /// Returns the file paths of all files of the given type in the content packages. + /// + /// + /// If true, also returns files in content packages that are installed but not currently selected. + public IEnumerable GetFilesOfType(ContentType type, bool searchAllContentPackages = false) + { + if (searchAllContentPackages) + { + return ContentPackage.GetFilesOfType(ContentPackage.List, type); + } + else + { + return ContentPackage.GetFilesOfType(SelectedPackages, type); + } + } + /// /// Returns the file paths of all files of the given type in the currently selected content packages. /// diff --git a/Barotrauma/BarotraumaShared/Source/Map/Md5Hash.cs b/Barotrauma/BarotraumaShared/Source/Map/Md5Hash.cs index 47b1d3a26..e1e2c8776 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Md5Hash.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Md5Hash.cs @@ -8,44 +8,28 @@ namespace Barotrauma { public class Md5Hash { - private string hash; - private string shortHash; + public string Hash { get; private set; } - public string Hash - { - get - { - return hash; - } - } - - public string ShortHash - { - get - { - return shortHash; - } - } + public string ShortHash { get; private set; } public Md5Hash(string md5Hash) { - this.hash = md5Hash; - - shortHash = GetShortHash(md5Hash); + this.Hash = md5Hash; + ShortHash = GetShortHash(md5Hash); } public Md5Hash(byte[] bytes) { - hash = CalculateHash(bytes); + Hash = CalculateHash(bytes); - shortHash = GetShortHash(hash); + ShortHash = GetShortHash(Hash); } public Md5Hash(FileStream fileStream) { - hash = CalculateHash(fileStream); + Hash = CalculateHash(fileStream); - shortHash = GetShortHash(hash); + ShortHash = GetShortHash(Hash); } public Md5Hash(XDocument doc) @@ -56,14 +40,14 @@ namespace Barotrauma byte[] inputBytes = Encoding.ASCII.GetBytes(docString); - hash = CalculateHash(inputBytes); + Hash = CalculateHash(inputBytes); - shortHash = GetShortHash(hash); + ShortHash = GetShortHash(Hash); } public override string ToString() { - return hash; + return Hash; } private string CalculateHash(FileStream stream)