Reapply "OBT1.1.0 Merge branch 'dev_pte' into dev"

This reverts commit 046483b9da.
This commit is contained in:
NotAlwaysTrue
2026-04-30 21:59:54 +08:00
parent 02689d0d86
commit 25683dcf39
85 changed files with 2413 additions and 779 deletions
@@ -1,10 +1,12 @@
using Microsoft.Xna.Framework;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using Barotrauma.IO;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Barotrauma.Extensions;
@@ -117,8 +119,9 @@ namespace Barotrauma
public virtual AnimationType AnimationType { get; protected set; }
/// <summary>
/// The cached animations of all the characters that have been loaded.
/// Thread-safe cache using ConcurrentDictionary.
/// </summary>
private static readonly Dictionary<Identifier, Dictionary<string, AnimationParams>> allAnimations = new Dictionary<Identifier, Dictionary<string, AnimationParams>>();
private static readonly ConcurrentDictionary<Identifier, ConcurrentDictionary<string, AnimationParams>> allAnimations = new ConcurrentDictionary<Identifier, ConcurrentDictionary<string, AnimationParams>>();
[Header("Movement")]
[Serialize(1.0f, IsPropertySaveable.Yes), Editable(DecimalCount = 2, MinValueFloat = 0, MaxValueFloat = Ragdoll.MAX_SPEED, ValueStep = 0.1f)]
@@ -244,7 +247,9 @@ namespace Barotrauma
return GetAnimParams<T>(speciesName, animSpecies, fallbackSpecies: character.Prefab.GetBaseCharacterSpeciesName(speciesName), animType, file, throwErrors);
}
private static readonly List<string> errorMessages = new List<string>();
// ThreadLocal for thread-safe error message collection during animation loading
private static readonly ThreadLocal<List<string>> errorMessagesLocal = new ThreadLocal<List<string>>(() => new List<string>());
private static List<string> errorMessages => errorMessagesLocal.Value;
private static T GetAnimParams<T>(Identifier speciesName, Identifier animSpecies, Identifier fallbackSpecies, AnimationType animType, Either<string, ContentPath> file, bool throwErrors = true) where T : AnimationParams, new()
{
@@ -262,11 +267,7 @@ namespace Barotrauma
}
ContentPackage contentPackage = contentPath?.ContentPackage ?? CharacterPrefab.FindBySpeciesName(speciesName)?.ContentPackage;
Debug.Assert(contentPackage != null);
if (!allAnimations.TryGetValue(speciesName, out Dictionary<string, AnimationParams> animations))
{
animations = new Dictionary<string, AnimationParams>();
allAnimations.Add(speciesName, animations);
}
var animations = allAnimations.GetOrAdd(speciesName, _ => new ConcurrentDictionary<string, AnimationParams>());
string key = fileName ?? contentPath?.Value ?? GetDefaultFileName(animSpecies, animType);
if (animations.TryGetValue(key, out AnimationParams anim) && anim.AnimationType == animType)
{
@@ -418,16 +419,12 @@ namespace Barotrauma
{
throw new Exception("Cannot create an animation file of type " + animationType);
}
if (!allAnimations.TryGetValue(speciesName, out Dictionary<string, AnimationParams> anims))
{
anims = new Dictionary<string, AnimationParams>();
allAnimations.Add(speciesName, anims);
}
var anims = allAnimations.GetOrAdd(speciesName, _ => new ConcurrentDictionary<string, AnimationParams>());
string fileName = IO.Path.GetFileNameWithoutExtension(fullPath);
if (anims.ContainsKey(fileName))
{
DebugConsole.NewMessage($"[AnimationParams] Removing the old animation of type {animationType}.", Color.Red);
anims.Remove(fileName);
anims.TryRemove(fileName, out _);
}
var instance = new T();
XElement animationElement = new XElement(GetDefaultFileName(speciesName, animationType), new XAttribute("animationtype", animationType.ToString()));
@@ -439,7 +436,7 @@ namespace Barotrauma
instance.IsLoaded = instance.Deserialize(animationElement);
instance.Save();
instance.Load(contentPath, speciesName);
anims.Add(fileName, instance);
anims.TryAdd(fileName, instance);
DebugConsole.NewMessage($"[AnimationParams] New animation file of type {animationType} created.", Color.GhostWhite);
return instance;
}
@@ -467,17 +464,14 @@ namespace Barotrauma
{
// Update the key by removing and re-adding the animation.
string fileName = FileNameWithoutExtension;
if (allAnimations.TryGetValue(SpeciesName, out Dictionary<string, AnimationParams> animations))
if (allAnimations.TryGetValue(SpeciesName, out ConcurrentDictionary<string, AnimationParams> animations))
{
animations.Remove(fileName);
animations.TryRemove(fileName, out _);
}
base.UpdatePath(newPath);
if (animations != null)
{
if (!animations.ContainsKey(fileName))
{
animations.Add(fileName, this);
}
animations.TryAdd(fileName, this);
}
}
}
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Linq;
@@ -124,8 +125,9 @@ namespace Barotrauma
/// key1: Species name
/// key2: File path
/// value: Ragdoll parameters
/// Thread-safe cache using ConcurrentDictionary.
/// </summary>
private static readonly Dictionary<Identifier, Dictionary<string, RagdollParams>> allRagdolls = new Dictionary<Identifier, Dictionary<string, RagdollParams>>();
private static readonly ConcurrentDictionary<Identifier, ConcurrentDictionary<string, RagdollParams>> allRagdolls = new ConcurrentDictionary<Identifier, ConcurrentDictionary<string, RagdollParams>>();
public List<ColliderParams> Colliders { get; private set; } = new List<ColliderParams>();
public List<LimbParams> Limbs { get; private set; } = new List<LimbParams>();
@@ -222,11 +224,7 @@ namespace Barotrauma
Debug.Assert(!fileName.IsNullOrWhiteSpace() || !contentPath.IsNullOrWhiteSpace());
}
Debug.Assert(contentPackage != null);
if (!allRagdolls.TryGetValue(speciesName, out Dictionary<string, RagdollParams> ragdolls))
{
ragdolls = new Dictionary<string, RagdollParams>();
allRagdolls.Add(speciesName, ragdolls);
}
var ragdolls = allRagdolls.GetOrAdd(speciesName, _ => new ConcurrentDictionary<string, RagdollParams>());
string key = fileName ?? contentPath?.Value ?? GetDefaultFileName(ragdollSpecies);
if (ragdolls.TryGetValue(key, out RagdollParams ragdoll))
{
@@ -331,10 +329,10 @@ namespace Barotrauma
if (allRagdolls.ContainsKey(speciesName))
{
DebugConsole.NewMessage($"[RagdollParams] Removing the old ragdolls from {speciesName}.", Color.Red);
allRagdolls.Remove(speciesName);
allRagdolls.TryRemove(speciesName, out _);
}
var ragdolls = new Dictionary<string, RagdollParams>();
allRagdolls.Add(speciesName, ragdolls);
var ragdolls = new ConcurrentDictionary<string, RagdollParams>();
allRagdolls.TryAdd(speciesName, ragdolls);
var instance = new T
{
doc = new XDocument(mainElement)
@@ -345,7 +343,7 @@ namespace Barotrauma
instance.IsLoaded = instance.Deserialize(mainElement);
instance.Save();
instance.Load(contentPath, speciesName);
ragdolls.Add(instance.FileNameWithoutExtension, instance);
ragdolls.TryAdd(instance.FileNameWithoutExtension, instance);
DebugConsole.NewMessage("[RagdollParams] New default ragdoll params successfully created at " + fullPath, Color.NavajoWhite);
return instance;
}
@@ -362,17 +360,14 @@ namespace Barotrauma
{
// Update the key by removing and re-adding the ragdoll.
string fileName = FileNameWithoutExtension;
if (allRagdolls.TryGetValue(SpeciesName, out Dictionary<string, RagdollParams> ragdolls))
if (allRagdolls.TryGetValue(SpeciesName, out ConcurrentDictionary<string, RagdollParams> ragdolls))
{
ragdolls.Remove(fileName);
ragdolls.TryRemove(fileName, out _);
}
base.UpdatePath(fullPath);
if (ragdolls != null)
{
if (!ragdolls.ContainsKey(fileName))
{
ragdolls.Add(fileName, this);
}
ragdolls.TryAdd(fileName, this);
}
}
}
@@ -1484,4 +1479,4 @@ namespace Barotrauma
}
#endregion
}
}
}