(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:
@@ -4,6 +4,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
#if CLIENT
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -86,10 +91,52 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private TargetType targetTypes;
|
||||
protected HashSet<string> targetIdentifiers;
|
||||
|
||||
public readonly ItemPrefab ItemPrefab;
|
||||
public readonly SpawnPositionType SpawnPosition;
|
||||
public readonly float Speed;
|
||||
public readonly float Rotation;
|
||||
|
||||
public ItemSpawnInfo(XElement element, string parentDebugName)
|
||||
{
|
||||
if (element.Attribute("name") != null)
|
||||
{
|
||||
//backwards compatibility
|
||||
DebugConsole.ThrowError("Error in StatusEffect config (" + element.ToString() + ") - use item identifier instead of the name.");
|
||||
string itemPrefabName = element.GetAttributeString("name", "");
|
||||
ItemPrefab = MapEntityPrefab.List.Find(m => m is ItemPrefab && (m.NameMatches(itemPrefabName) || m.Tags.Contains(itemPrefabName))) as ItemPrefab;
|
||||
if (ItemPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in StatusEffect \""+ parentDebugName + "\" - item prefab \"" + itemPrefabName + "\" not found.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string itemPrefabIdentifier = element.GetAttributeString("identifier", "");
|
||||
if (string.IsNullOrEmpty(itemPrefabIdentifier)) itemPrefabIdentifier = element.GetAttributeString("identifiers", "");
|
||||
if (string.IsNullOrEmpty(itemPrefabIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid item spawn in StatusEffect \"" + parentDebugName + "\" - identifier not found in the element \"" + element.ToString() + "\"");
|
||||
}
|
||||
ItemPrefab = MapEntityPrefab.List.Find(m => m is ItemPrefab && m.Identifier == itemPrefabIdentifier) as ItemPrefab;
|
||||
if (ItemPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in StatusEffect config - item prefab with the identifier \"" + itemPrefabIdentifier + "\" not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Speed = element.GetAttributeFloat("speed", 0.0f);
|
||||
Rotation = MathHelper.ToRadians(element.GetAttributeFloat("rotation", 0.0f));
|
||||
|
||||
private List<RoundSound> sounds = new List<RoundSound>();
|
||||
private SoundSelectionMode soundSelectionMode;
|
||||
private SoundChannel soundChannel;
|
||||
private bool loopSound;
|
||||
#endif
|
||||
|
||||
private List<RelatedItem> requiredItems;
|
||||
|
||||
public string[] propertyNames;
|
||||
@@ -181,6 +228,10 @@ namespace Barotrauma
|
||||
|
||||
Range = element.GetAttributeFloat("range", 0.0f);
|
||||
|
||||
#if CLIENT
|
||||
particleEmitters = new List<ParticleEmitter>();
|
||||
#endif
|
||||
|
||||
IEnumerable<XAttribute> attributes = element.Attributes();
|
||||
List<XAttribute> propertyAttributes = new List<XAttribute>();
|
||||
propertyConditionals = new List<PropertyConditional>();
|
||||
@@ -357,6 +408,25 @@ namespace Barotrauma
|
||||
var newSpawnItem = new ItemSpawnInfo(subElement, parentDebugName);
|
||||
if (newSpawnItem.ItemPrefab != null) spawnItems.Add(newSpawnItem);
|
||||
break;
|
||||
#if CLIENT
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
case "sound":
|
||||
var sound = Submarine.LoadRoundSound(subElement);
|
||||
if (sound != null)
|
||||
{
|
||||
loopSound = subElement.GetAttributeBool("loop", false);
|
||||
if (subElement.Attribute("selectionmode") != null)
|
||||
{
|
||||
if (Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode))
|
||||
{
|
||||
soundSelectionMode = selectionMode;
|
||||
}
|
||||
}
|
||||
sounds.Add(sound);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitProjSpecific(element, parentDebugName);
|
||||
@@ -369,6 +439,11 @@ namespace Barotrauma
|
||||
return (targetTypes & targetType) != 0;
|
||||
}
|
||||
|
||||
public bool HasTargetType(TargetType targetType)
|
||||
{
|
||||
return (targetTypes & targetType) != 0;
|
||||
}
|
||||
|
||||
public virtual bool HasRequiredItems(Entity entity)
|
||||
{
|
||||
if (requiredItems == null) return true;
|
||||
@@ -568,10 +643,46 @@ namespace Barotrauma
|
||||
{
|
||||
hull = ((Item)entity).CurrentHull;
|
||||
}
|
||||
#if CLIENT
|
||||
if (entity != null && sounds.Count > 0)
|
||||
{
|
||||
if (soundChannel == null || !soundChannel.IsPlaying)
|
||||
{
|
||||
if (soundSelectionMode == SoundSelectionMode.All)
|
||||
{
|
||||
foreach (RoundSound sound in sounds)
|
||||
{
|
||||
soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull);
|
||||
if (soundChannel != null) soundChannel.Looping = loopSound;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int selectedSoundIndex = 0;
|
||||
if (soundSelectionMode == SoundSelectionMode.ItemSpecific && entity is Item item)
|
||||
{
|
||||
selectedSoundIndex = item.ID % sounds.Count;
|
||||
}
|
||||
else if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && entity is Character user)
|
||||
{
|
||||
selectedSoundIndex = user.ID % sounds.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedSoundIndex = Rand.Int(sounds.Count);
|
||||
}
|
||||
var selectedSound = sounds[selectedSoundIndex];
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull);
|
||||
if (soundChannel != null) soundChannel.Looping = loopSound;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
foreach (ISerializableEntity serializableEntity in targets)
|
||||
{
|
||||
if (!(serializableEntity is Item item)) continue;
|
||||
Item item = serializableEntity as Item;
|
||||
if (item == null) continue;
|
||||
|
||||
Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character;
|
||||
if (targetCharacter == null)
|
||||
@@ -671,7 +782,11 @@ namespace Barotrauma
|
||||
fire.Size = new Vector2(FireSize, fire.Size.Y);
|
||||
}
|
||||
|
||||
bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
|
||||
bool isNotClient = true;
|
||||
#if CLIENT
|
||||
isNotClient = GameMain.Client == null;
|
||||
#endif
|
||||
|
||||
if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items
|
||||
{
|
||||
foreach (ItemSpawnInfo itemSpawnInfo in spawnItems)
|
||||
@@ -728,11 +843,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (entity != null)
|
||||
{
|
||||
foreach (ParticleEmitter emitter in particleEmitters)
|
||||
{
|
||||
float angle = 0.0f;
|
||||
if (emitter.Prefab.CopyEntityAngle)
|
||||
{
|
||||
if (entity is Item it)
|
||||
{
|
||||
angle = it.body == null ? 0.0f : it.body.Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
emitter.Emit(deltaTime, entity.WorldPosition, hull, angle);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyProjSpecific(deltaTime, entity, targets, hull);
|
||||
}
|
||||
|
||||
partial void ApplyProjSpecific(float deltaTime, Entity entity, List<ISerializableEntity> targets, Hull currentHull);
|
||||
|
||||
private void ApplyToProperty(ISerializableEntity target, SerializableProperty property, object value, float deltaTime)
|
||||
{
|
||||
if (disableDeltaTime || setValue) deltaTime = 1.0f;
|
||||
|
||||
Reference in New Issue
Block a user