From 1eb8d2bd88fb996bc3f2683d3e286f6341d136b1 Mon Sep 17 00:00:00 2001 From: Eman Date: Sat, 21 Sep 2024 18:26:22 +0200 Subject: [PATCH 1/4] Character flipping enhancements Made changes to networking to properly sync characters' flipped state in a multiplayer server Made player controlled monsters not turn in the direction of the mouse or turn instantly in multiplayer, instead they will need to walk in the opposite direction and wait for the animation's flip timers before turning around. Added "flipcharacter" status effect command to make a character flip. Mainly only useful for non-humanoids, for example, to make them spawn already flipped through some conditions. Made "spawncharacter" status effect command and husk infection spawn the new characters already flipped if the target character is also flipped. --- .../Characters/CharacterNetworking.cs | 11 ++++++- .../Characters/CharacterNetworking.cs | 3 +- .../Animation/FishAnimController.cs | 13 ++++----- .../SharedSource/Characters/Character.cs | 29 +++++++++++++++---- .../Health/Afflictions/AfflictionHusk.cs | 4 +++ .../StatusEffects/StatusEffect.cs | 25 ++++++++++++++-- 6 files changed, 68 insertions(+), 17 deletions(-) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index ee0137f930..537f69edb8 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -220,7 +220,16 @@ public void ClientReadPosition(IReadMessage msg, float sendingTime) keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); - facingRight = msg.ReadBoolean(); + } + + facingRight = msg.ReadBoolean(); + + if (AnimController.IsFlipped == facingRight) + { + if((AnimController is HumanoidAnimController && !CanMove) || AnimController is FishAnimController) + { + TryFlipCharacter(); + } } bool entitySelected = msg.ReadBoolean(); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index 9d5bce1a68..f96ca06a4b 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -386,9 +386,10 @@ public void ServerWritePosition(ReadWriteMessage tempBuffer, Client c) tempBuffer.WriteBoolean(IsRagdolled || Stun > 0.0f || IsDead || IsIncapacitated); - tempBuffer.WriteBoolean(AnimController.Dir > 0.0f); } + tempBuffer.WriteBoolean(AnimController.Dir > 0.0f); + if (SelectedCharacter != null || HasSelectedAnyItem) { tempBuffer.WriteBoolean(true); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs index fa20dd94cb..d1d781cfd7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs @@ -281,7 +281,7 @@ protected override void UpdateAnim(float deltaTime) } } - if (!IsStuck && CurrentFishAnimation.Flip && character.AIController is not { CanFlip: false }) + if (!IsStuck && CurrentFishAnimation.Flip && character.AIController is not { CanFlip: false } && (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)) { flipCooldown -= deltaTime; if (TargetDir != Direction.None && TargetDir != dir) @@ -296,14 +296,9 @@ protected override void UpdateAnim(float deltaTime) } bool isMovingFastEnough = Math.Abs(MainLimb.LinearVelocity.X) > requiredSpeed; bool isTryingToMoveHorizontally = Math.Abs(TargetMovement.X) > Math.Abs(TargetMovement.Y); - if ((flipTimer > CurrentFishAnimation.FlipDelay && flipCooldown <= 0.0f && ((isMovingFastEnough && isTryingToMoveHorizontally) || IsMovingBackwards)) - || character.IsRemotePlayer) + if ((flipTimer > CurrentFishAnimation.FlipDelay && flipCooldown <= 0.0f) && ((isMovingFastEnough && isTryingToMoveHorizontally) || IsMovingBackwards)) { Flip(); - if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror)) - { - Mirror(CurrentSwimParams != null ? CurrentSwimParams.MirrorLerp : true); - } flipTimer = 0.0f; flipCooldown = CurrentFishAnimation.FlipCooldown; } @@ -1029,6 +1024,10 @@ public override void Flip() //no need to do anything when flipping vertically oriented limbs //the sprite gets flipped horizontally, which does the job } + if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror)) + { + Mirror(CurrentSwimParams != null ? CurrentSwimParams.MirrorLerp : true); + } } public void Mirror(bool lerp = true) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 6e2a69bc8d..8fe5a4daa9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -2111,11 +2111,7 @@ public void Control(float deltaTime, Camera cam) ((!IsClimbing && AnimController.OnGround) || (IsClimbing && IsKeyDown(InputType.Aim))) && !AnimController.InWater) { - if (dontFollowCursor) - { - AnimController.TargetDir = Direction.Right; - } - else + if (AnimController is not FishAnimController) { if (CursorPosition.X < AnimController.Collider.Position.X - cursorFollowMargin) { @@ -2126,6 +2122,10 @@ public void Control(float deltaTime, Camera cam) AnimController.TargetDir = Direction.Right; } } + if (AnimController is HumanoidAnimController && dontFollowCursor) // For character editor + { + AnimController.TargetDir = Direction.Right; + } } if (GameMain.NetworkMember != null) @@ -5808,6 +5808,25 @@ public void StopClimbing() AnimController.StopClimbing(); ReleaseSecondaryItem(); } + + public void TryFlipCharacter() + { + if (AnimController is FishAnimController fishAnimController) + { + if (fishAnimController.CurrentFishAnimation.Flip) + { + fishAnimController.Flip(); + } + } + else + { + AnimController.TargetDir = (AnimController.TargetDir == Direction.Left) ? Direction.Right : Direction.Left; + if (!CanMove) + { + AnimController.Flip(); + } + } + } } class ActiveTeamChange diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs index a4338ac70a..d066609dae 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs @@ -372,6 +372,10 @@ private IEnumerable CreateAIHusk() } husk.SetStun(5); + if (character.IsFlipped) + { + husk.TryFlipCharacter(); + } yield return new WaitForSeconds(5, false); #if CLIENT husk?.PlaySound(CharacterSound.SoundType.Idle); diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index e7d287f790..7433f55e53 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -603,7 +603,7 @@ public AITrigger(XElement element) private readonly int useItemCount; - private readonly bool removeItem, dropContainedItems, dropItem, removeCharacter, breakLimb, hideLimb; + private readonly bool removeItem, dropContainedItems, dropItem, removeCharacter, breakLimb, hideLimb, flipCharacter; private readonly float hideLimbTimer; public readonly ActionType type = ActionType.OnActive; @@ -968,6 +968,9 @@ protected StatusEffect(ContentXElement element, string parentDebugName) case "removecharacter": removeCharacter = true; break; + case "flipcharacter": + flipCharacter = true; + break; case "breaklimb": breakLimb = true; break; @@ -1603,6 +1606,9 @@ protected void Apply(float deltaTime, Entity entity, IReadOnlyList 0) { Character useTargetCharacter = null; @@ -1687,6 +1693,17 @@ protected void Apply(float deltaTime, Entity entity, IReadOnlyList Date: Wed, 23 Oct 2024 01:54:24 +0200 Subject: [PATCH 2/4] Remove unnecessary changes --- .../ClientSource/Characters/CharacterNetworking.cs | 11 +---------- .../ServerSource/Characters/CharacterNetworking.cs | 3 +-- .../Characters/Animation/FishAnimController.cs | 13 +++++++------ .../SharedSource/Characters/Character.cs | 14 ++++++++++++++ .../SharedSource/StatusEffects/StatusEffect.cs | 2 +- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index 2c053f9886..5ef1cebff5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -227,16 +227,7 @@ public void ClientReadPosition(IReadMessage msg, float sendingTime) keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); - } - - facingRight = msg.ReadBoolean(); - - if (AnimController.IsFlipped == facingRight) - { - if((AnimController is HumanoidAnimController && !CanMove) || AnimController is FishAnimController) - { - TryFlipCharacter(); - } + facingRight = msg.ReadBoolean(); } bool entitySelected = msg.ReadBoolean(); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index 3583bd21ae..6d8c1801ee 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -404,10 +404,9 @@ public void ServerWritePosition(ReadWriteMessage tempBuffer, Client c) tempBuffer.WriteBoolean(IsRagdolled || Stun > 0.0f || IsDead || IsIncapacitated); + tempBuffer.WriteBoolean(AnimController.Dir > 0.0f); } - tempBuffer.WriteBoolean(AnimController.Dir > 0.0f); - if (SelectedCharacter != null || HasSelectedAnyItem) { tempBuffer.WriteBoolean(true); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs index 221934f0a6..5a6cb8e323 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs @@ -288,7 +288,7 @@ protected override void UpdateAnim(float deltaTime) } } - if (!IsStuck && CurrentFishAnimation.Flip && character.AIController is not { CanFlip: false } && (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)) + if (!IsStuck && CurrentFishAnimation.Flip && character.AIController is not { CanFlip: false }) { flipCooldown -= deltaTime; if (TargetDir != Direction.None && TargetDir != dir) @@ -303,9 +303,14 @@ protected override void UpdateAnim(float deltaTime) } bool isMovingFastEnough = Math.Abs(MainLimb.LinearVelocity.X) > requiredSpeed; bool isTryingToMoveHorizontally = Math.Abs(TargetMovement.X) > Math.Abs(TargetMovement.Y); - if ((flipTimer > CurrentFishAnimation.FlipDelay && flipCooldown <= 0.0f) && ((isMovingFastEnough && isTryingToMoveHorizontally) || IsMovingBackwards)) + if ((flipTimer > CurrentFishAnimation.FlipDelay && flipCooldown <= 0.0f && ((isMovingFastEnough && isTryingToMoveHorizontally) || IsMovingBackwards)) + || character.IsRemotePlayer) { Flip(); + if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror)) + { + Mirror(CurrentSwimParams != null ? CurrentSwimParams.MirrorLerp : true); + } flipTimer = 0.0f; flipCooldown = CurrentFishAnimation.FlipCooldown; } @@ -995,10 +1000,6 @@ public override void Flip() //no need to do anything when flipping vertically oriented limbs //the sprite gets flipped horizontally, which does the job } - if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror)) - { - Mirror(CurrentSwimParams != null ? CurrentSwimParams.MirrorLerp : true); - } } public void Mirror(bool lerp = true) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 8e75cc189a..c5cb63a0f5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -5994,6 +5994,20 @@ public void StopClimbing() AnimController.StopClimbing(); ReleaseSecondaryItem(); } + public void TryFlipCharacter() + { + if (AnimController is FishAnimController fishAnimController) + { + if (fishAnimController.CurrentFishAnimation.Flip) + { + fishAnimController.Flip(); + } + } + else + { + AnimController.Flip(); + } + } } class ActiveTeamChange diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 23a3ac45af..d7a93592fa 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -1758,7 +1758,7 @@ protected void Apply(float deltaTime, Entity entity, IReadOnlyList Date: Wed, 23 Oct 2024 01:56:27 +0200 Subject: [PATCH 3/4] Move isnotclient check outside of for loop --- .../SharedSource/StatusEffects/StatusEffect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index d7a93592fa..bdcb7408c7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -1754,12 +1754,12 @@ protected void Apply(float deltaTime, Entity entity, IReadOnlyList Date: Wed, 23 Oct 2024 02:21:14 +0200 Subject: [PATCH 4/4] 50% chance to spawn corpses flipped --- Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index ef426fdb44..5ba2bd926a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -4973,6 +4973,10 @@ public void SpawnCorpses() corpse.EnableDespawn = false; selectedPrefab.GiveItems(corpse, wreck, sp); bool spawnAsHusk = Rand.Value() <= Loaded.GenerationParams.HuskProbability; + if(Rand.Value() <= 0.5) + { + corpse.TryFlipCharacter(); // Random chance to spawn flipped + } if (spawnAsHusk) { corpse.TurnIntoHusk(playDead: true);