v1.7.7.0 (Winter Update 2024)

This commit is contained in:
Regalis11
2024-12-11 13:26:13 +02:00
parent 7d5b7a310a
commit f6349b2175
256 changed files with 4794 additions and 1653 deletions
@@ -189,7 +189,7 @@ namespace Barotrauma
CharacterPrefab prefab = CharacterPrefab.FindBySpeciesName(speciesName);
if (prefab?.ConfigElement == null)
{
DebugConsole.ThrowError($"Failed to find config file for '{speciesName}'");
DebugConsole.ThrowError($"Failed to find config file for '{speciesName}'", contentPackage: prefab?.ContentPackage);
return string.Empty;
}
return GetFolder(prefab.ConfigElement, prefab.FilePath.Value);
@@ -414,7 +414,7 @@ namespace Barotrauma
{
if (animationType == AnimationType.NotDefined)
{
throw new Exception("Cannot create an animation file of type " + animationType.ToString());
throw new Exception("Cannot create an animation file of type " + animationType);
}
if (!allAnimations.TryGetValue(speciesName, out Dictionary<string, AnimationParams> anims))
{
@@ -543,7 +543,7 @@ namespace Barotrauma
{
if (doc == null)
{
DebugConsole.ThrowError("[AnimationParams] The source XML Document is null!");
DebugConsole.ThrowError("[AnimationParams] The source XML Document is null!", contentPackage: Path.ContentPackage);
return;
}
Serialize();
@@ -193,25 +193,32 @@ namespace Barotrauma
{
return newXml;
}
// CreateVariantXML seems to merge the ai targets so that in the new xml we have both the old and the new target definitions.
// CreateVariantXML does not understand anything about targeting tags, it just replaces the <target> elements in the order they're defined in.
// We can do better here by replacing the target with a matching tag, so let's clear the element and do that.
var finalAiElement = newXml.GetChildElement("ai");
var processedTags = new HashSet<string>();
foreach (var aiTarget in finalAiElement.Elements().ToArray())
finalAiElement.Elements().Remove();
//add all the targets from the base character
baseAi.Elements().ForEach(e => finalAiElement.Add(e));
var processedTags = new List<Identifier>();
foreach (var variantTargetElement in variantAi.Elements())
{
string tag = aiTarget.GetAttributeString("tag", null);
if (tag == null) { continue; }
if (processedTags.Contains(tag))
Identifier tag = variantTargetElement.GetAttributeIdentifier("tag", Identifier.Empty);
var matchingElements = finalAiElement.Elements().Where(e => e.GetAttributeIdentifier("tag", Identifier.Empty) == tag);
int alreadyProcessed = processedTags.Count(t => t == tag);
if (matchingElements.Count() > alreadyProcessed)
{
aiTarget.Remove();
continue;
//more matching elements found, replace the first one that hasn't been processed yet
matchingElements.Skip(alreadyProcessed).First().ReplaceWith(variantTargetElement);
}
else
{
//no more matching elements in the base XML, this must be a new target
finalAiElement.Add(variantTargetElement);
}
processedTags.Add(tag);
var matchInSelf = variantAi.Elements().FirstOrDefault(e => e.GetAttributeString("tag", null) == tag);
var matchInParent = baseAi.Elements().FirstOrDefault(e => e.GetAttributeString("tag", null) == tag);
if (matchInSelf != null && matchInParent != null)
{
aiTarget.ReplaceWith(new XElement(matchInSelf));
}
}
return newXml;
}
@@ -137,15 +137,14 @@ namespace Barotrauma
.Concat(Joints);
public static string GetDefaultFileName(Identifier speciesName) => $"{speciesName.Value.CapitaliseFirstInvariant()}DefaultRagdoll";
public static string GetDefaultFile(Identifier speciesName, ContentPackage contentPackage = null)
=> IO.Path.Combine(GetFolder(speciesName, contentPackage), $"{GetDefaultFileName(speciesName)}.xml");
public static string GetFolder(Identifier speciesName, ContentPackage contentPackage = null)
public static string GetDefaultFile(Identifier speciesName) => IO.Path.Combine(GetFolder(speciesName), $"{GetDefaultFileName(speciesName)}.xml");
public static string GetFolder(Identifier speciesName)
{
CharacterPrefab prefab = CharacterPrefab.Find(p => p.Identifier == speciesName && (contentPackage == null || p.ContentFile.ContentPackage == contentPackage));
CharacterPrefab prefab = CharacterPrefab.FindBySpeciesName(speciesName);
if (prefab?.ConfigElement == null)
{
DebugConsole.ThrowError($"Failed to find config file for '{speciesName}'", contentPackage: contentPackage);
DebugConsole.ThrowError($"Failed to find config file for '{speciesName}'");
return string.Empty;
}
return GetFolder(prefab.ConfigElement, prefab.ContentFile.Path.Value);
@@ -199,10 +198,10 @@ namespace Barotrauma
}
}
}
else if (!variantOf.IsEmpty && CharacterPrefab.FindBySpeciesName(variantOf) is CharacterPrefab prefab)
else if (!variantOf.IsEmpty && CharacterPrefab.FindBySpeciesName(variantOf) is CharacterPrefab parentPrefab)
{
// Ragdoll element not defined -> use the ragdoll defined in the base definition file.
ragdollSpecies = prefab.GetBaseCharacterSpeciesName(variantOf);
//get the params from the parent prefab if this one doesn't re-define them
return GetDefaultRagdollParams<T>(variantOf, parentPrefab.ConfigElement, parentPrefab.ContentPackage);
}
// Using a null file definition means we use the default animations found in the Ragdolls folder.
return GetRagdollParams<T>(speciesName, ragdollSpecies, file: null, contentPackage);
@@ -245,7 +244,7 @@ namespace Barotrauma
}
else
{
DebugConsole.ThrowError($"[AnimationParams] Failed to load an animation {ragdollInstance} from {contentPath.Value} for the character {speciesName}. Using the default ragdoll.", contentPackage: contentPackage);
DebugConsole.ThrowError($"[RagdollParams] Failed to load a ragdoll {ragdollInstance} from {contentPath.Value} for the character {speciesName}. Using the default ragdoll.", contentPackage: contentPackage);
}
}
// Seek the default ragdoll from the character's ragdoll folder.
@@ -294,8 +293,30 @@ namespace Barotrauma
}
else
{
// Failing to create a ragdoll causes so many issues that cannot be handled. Dummy ragdoll just seems to make things harder to debug. It's better to fail early.
throw new Exception($"[RagdollParams] Failed to load ragdoll {r.Name} from {selectedFile} for the character {speciesName}.");
string error = $"[RagdollParams] Failed to load ragdoll {r.Name} from {selectedFile} for the character {speciesName}.";
if (contentPackage == GameMain.VanillaContent)
{
// Check if the base character content package is vanilla too.
CharacterPrefab characterPrefab = CharacterPrefab.FindBySpeciesName(speciesName);
if (characterPrefab?.ParentPrefab == null || characterPrefab.ParentPrefab.ContentPackage == GameMain.VanillaContent)
{
// If the error is in the vanilla content, it's just better to crash early.
// If dodging with the solution below fails, we'll also get here.
throw new Exception(error);
}
}
// Try to dodge crashing on modded content.
DebugConsole.ThrowError(error, contentPackage: contentPackage);
if (typeof(T) == typeof(HumanRagdollParams))
{
Identifier fallbackSpecies = CharacterPrefab.HumanSpeciesName;
r = GetRagdollParams<T>(fallbackSpecies, fallbackSpecies, file: ContentPath.FromRaw(contentPackage, "Content/Characters/Human/Ragdolls/HumanDefaultRagdoll.xml"), contentPackage: GameMain.VanillaContent);
}
else
{
Identifier fallbackSpecies = "crawler".ToIdentifier();
r = GetRagdollParams<T>(fallbackSpecies, fallbackSpecies, file: ContentPath.FromRaw(contentPackage, "Content/Characters/Crawler/Ragdolls/CrawlerDefaultRagdoll.xml"), contentPackage: GameMain.VanillaContent);
}
}
return r;
}
@@ -869,6 +890,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes, description: "Can the limb enter submarines? Only valid if the ragdoll's CanEnterSubmarine is set to Partial, otherwise the limb can enter if the ragdoll can."), Editable]
public bool CanEnterSubmarine { get; private set; }
[Serialize(LimbType.None, IsPropertySaveable.Yes, description: "When set to something else than None, this limb will be hidden if the limb of the specified type is hidden."), Editable]
public LimbType InheritHiding { get; set; }
public LimbParams(ContentXElement element, RagdollParams ragdoll) : base(element, ragdoll)
{
var spriteElement = element.GetChildElement("sprite");