Unstable 0.17.0.0

This commit is contained in:
Markus Isberg
2022-02-26 02:43:01 +09:00
parent a83f375681
commit 3974067915
913 changed files with 32472 additions and 32364 deletions
@@ -81,7 +81,7 @@ namespace Barotrauma
public string Name => Prefab?.Name ?? "LevelObject (null)";
public Dictionary<string, SerializableProperty> SerializableProperties { get; } = new Dictionary<string, SerializableProperty>();
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; } = new Dictionary<Identifier, SerializableProperty>();
public Level.Cave ParentCave;
@@ -93,7 +93,7 @@ namespace Barotrauma
Rotation = rotation;
Health = prefab.Health;
spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.Server) : -1;
spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.ServerAndClient) : -1;
if (Sprite != null && prefab.SpriteSpecificPhysicsBodyElements.ContainsKey(Sprite))
{
@@ -115,7 +115,7 @@ namespace Barotrauma
Physics.CollisionWall | Physics.CollisionCharacter;
}
foreach (XElement triggerElement in prefab.LevelTriggerElements)
foreach (var triggerElement in prefab.LevelTriggerElements)
{
Triggers ??= new List<LevelTrigger>();
Vector2 triggerPosition = triggerElement.GetAttributeVector2("position", Vector2.Zero) * scale;
@@ -147,7 +147,7 @@ namespace Barotrauma
if (overrideProperties == null) { continue; }
if (overrideProperties.Sprites.Count > 0)
{
spriteIndex = Rand.Int(overrideProperties.Sprites.Count, Rand.RandSync.Server);
spriteIndex = Rand.Int(overrideProperties.Sprites.Count, Rand.RandSync.ServerAndClient);
break;
}
}
@@ -7,7 +7,6 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Voronoi2;
using Barotrauma.Extensions;
@@ -140,7 +139,7 @@ namespace Barotrauma
new GraphEdge(level.EndPosition - Vector2.UnitX, level.EndPosition + Vector2.UnitX),
-Vector2.UnitY, LevelObjectPrefab.SpawnPosType.LevelEnd, Alignment.Top));
var availablePrefabs = new List<LevelObjectPrefab>(LevelObjectPrefab.List);
var availablePrefabs =LevelObjectPrefab.Prefabs.OrderBy(p => p.UintIdentifier).ToList();
objects = new List<LevelObject>();
updateableObjects = new List<LevelObject>();
@@ -167,7 +166,7 @@ namespace Barotrauma
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
}
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.ServerAndClient);
if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None) { continue; }
PlaceObject(prefab, spawnPosition, level);
if (prefab.MaxCount < amount)
@@ -181,7 +180,8 @@ namespace Barotrauma
foreach (Level.Cave cave in level.Caves)
{
availablePrefabs = new List<LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall)));
availablePrefabs = LevelObjectPrefab.Prefabs.Where(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall))
.OrderBy(p => p.UintIdentifier).ToList();
availableSpawnPositions.Clear();
suitableSpawnPositions.Clear();
spawnPositionWeights.Clear();
@@ -210,7 +210,7 @@ namespace Barotrauma
spawnPositionWeights.Add(prefab,
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
}
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.ServerAndClient);
if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None) { continue; }
PlaceObject(prefab, spawnPosition, level, cave);
if (prefab.MaxCount < amount)
@@ -228,7 +228,8 @@ namespace Barotrauma
{
Rand.SetSyncedSeed(ToolBox.StringToInt(level.Seed));
var availablePrefabs = new List<LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.NestWall)));
var availablePrefabs = LevelObjectPrefab.Prefabs.Where(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.NestWall))
.OrderBy(p => p.UintIdentifier).ToList();
Dictionary<LevelObjectPrefab, List<SpawnPosition>> suitableSpawnPositions = new Dictionary<LevelObjectPrefab, List<SpawnPosition>>();
Dictionary<LevelObjectPrefab, List<float>> spawnPositionWeights = new Dictionary<LevelObjectPrefab, List<float>>();
@@ -258,7 +259,7 @@ namespace Barotrauma
spawnPositionWeights.Add(prefab,
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
}
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.ServerAndClient);
if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None) { continue; }
PlaceObject(prefab, spawnPosition, level);
if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
@@ -275,49 +276,49 @@ namespace Barotrauma
{
rotation = MathUtils.VectorToAngle(new Vector2(spawnPosition.Normal.Y, spawnPosition.Normal.X));
}
rotation += Rand.Range(prefab.RandomRotationRad.X, prefab.RandomRotationRad.Y, Rand.RandSync.Server);
rotation += Rand.Range(prefab.RandomRotationRad.X, prefab.RandomRotationRad.Y, Rand.RandSync.ServerAndClient);
Vector2 position = Vector2.Zero;
Vector2 edgeDir = Vector2.UnitX;
if (spawnPosition == null)
{
position = new Vector2(
Rand.Range(0.0f, level.Size.X, Rand.RandSync.Server),
Rand.Range(0.0f, level.Size.Y, Rand.RandSync.Server));
Rand.Range(0.0f, level.Size.X, Rand.RandSync.ServerAndClient),
Rand.Range(0.0f, level.Size.Y, Rand.RandSync.ServerAndClient));
}
else
{
edgeDir = (spawnPosition.GraphEdge.Point1 - spawnPosition.GraphEdge.Point2) / spawnPosition.Length;
position = spawnPosition.GraphEdge.Point2 + edgeDir * Rand.Range(prefab.MinSurfaceWidth / 2.0f, spawnPosition.Length - prefab.MinSurfaceWidth / 2.0f, Rand.RandSync.Server);
position = spawnPosition.GraphEdge.Point2 + edgeDir * Rand.Range(prefab.MinSurfaceWidth / 2.0f, spawnPosition.Length - prefab.MinSurfaceWidth / 2.0f, Rand.RandSync.ServerAndClient);
}
if (!MathUtils.NearlyEqual(prefab.RandomOffset.X, 0.0f) || !MathUtils.NearlyEqual(prefab.RandomOffset.Y, 0.0f))
{
Vector2 offsetDir = spawnPosition.Normal.LengthSquared() > 0.001f ? spawnPosition.Normal : Rand.Vector(1.0f, Rand.RandSync.Server);
position += offsetDir * Rand.Range(prefab.RandomOffset.X, prefab.RandomOffset.Y, Rand.RandSync.Server);
Vector2 offsetDir = spawnPosition.Normal.LengthSquared() > 0.001f ? spawnPosition.Normal : Rand.Vector(1.0f, Rand.RandSync.ServerAndClient);
position += offsetDir * Rand.Range(prefab.RandomOffset.X, prefab.RandomOffset.Y, Rand.RandSync.ServerAndClient);
}
var newObject = new LevelObject(prefab,
new Vector3(position, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.Server)), Rand.Range(prefab.MinSize, prefab.MaxSize, Rand.RandSync.Server), rotation);
new Vector3(position, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.ServerAndClient)), Rand.Range(prefab.MinSize, prefab.MaxSize, Rand.RandSync.ServerAndClient), rotation);
AddObject(newObject, level);
newObject.ParentCave = parentCave;
foreach (LevelObjectPrefab.ChildObject child in prefab.ChildObjects)
{
int childCount = Rand.Range(child.MinCount, child.MaxCount + 1, Rand.RandSync.Server);
int childCount = Rand.Range(child.MinCount, child.MaxCount + 1, Rand.RandSync.ServerAndClient);
for (int j = 0; j < childCount; j++)
{
var matchingPrefabs = LevelObjectPrefab.List.Where(p => child.AllowedNames.Contains(p.Name));
var matchingPrefabs = LevelObjectPrefab.Prefabs.Where(p => child.AllowedNames.Contains(p.Name));
int prefabCount = matchingPrefabs.Count();
var childPrefab = prefabCount == 0 ? null : matchingPrefabs.ElementAt(Rand.Range(0, prefabCount, Rand.RandSync.Server));
var childPrefab = prefabCount == 0 ? null : matchingPrefabs.ElementAt(Rand.Range(0, prefabCount, Rand.RandSync.ServerAndClient));
if (childPrefab == null) { continue; }
Vector2 childPos = position + edgeDir * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server) * prefab.MinSurfaceWidth;
Vector2 childPos = position + edgeDir * Rand.Range(-0.5f, 0.5f, Rand.RandSync.ServerAndClient) * prefab.MinSurfaceWidth;
var childObject = new LevelObject(childPrefab,
new Vector3(childPos, Rand.Range(childPrefab.DepthRange.X, childPrefab.DepthRange.Y, Rand.RandSync.Server)),
Rand.Range(childPrefab.MinSize, childPrefab.MaxSize, Rand.RandSync.Server),
rotation + Rand.Range(childPrefab.RandomRotationRad.X, childPrefab.RandomRotationRad.Y, Rand.RandSync.Server));
new Vector3(childPos, Rand.Range(childPrefab.DepthRange.X, childPrefab.DepthRange.Y, Rand.RandSync.ServerAndClient)),
Rand.Range(childPrefab.MinSize, childPrefab.MaxSize, Rand.RandSync.ServerAndClient),
rotation + Rand.Range(childPrefab.RandomRotationRad.X, childPrefab.RandomRotationRad.Y, Rand.RandSync.ServerAndClient));
AddObject(childObject, level);
childObject.ParentCave = parentCave;
@@ -577,7 +578,7 @@ namespace Barotrauma
if (availablePrefabs.Sum(p => p.GetCommonness(generationParams)) <= 0.0f) { return null; }
return ToolBox.SelectWeightedRandom(
availablePrefabs,
availablePrefabs.Select(p => p.GetCommonness(generationParams)).ToList(), Rand.RandSync.Server);
availablePrefabs.Select(p => p.GetCommonness(generationParams)).ToList(), Rand.RandSync.ServerAndClient);
}
private LevelObjectPrefab GetRandomPrefab(CaveGenerationParams caveParams, IList<LevelObjectPrefab> availablePrefabs, bool requireCaveSpecificOverride)
@@ -585,7 +586,7 @@ namespace Barotrauma
if (availablePrefabs.Sum(p => p.GetCommonness(caveParams, requireCaveSpecificOverride)) <= 0.0f) { return null; }
return ToolBox.SelectWeightedRandom(
availablePrefabs,
availablePrefabs.Select(p => p.GetCommonness(caveParams, requireCaveSpecificOverride)).ToList(), Rand.RandSync.Server);
availablePrefabs.Select(p => p.GetCommonness(caveParams, requireCaveSpecificOverride)).ToList(), Rand.RandSync.ServerAndClient);
}
public override void Remove()
@@ -1,14 +1,15 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
partial class LevelObjectPrefab : ISerializableEntity
partial class LevelObjectPrefab : PrefabWithUintIdentifier, ISerializableEntity
{
public static List<LevelObjectPrefab> List { get; } = new List<LevelObjectPrefab>();
public readonly static PrefabCollection<LevelObjectPrefab> Prefabs = new PrefabCollection<LevelObjectPrefab>();
public class ChildObject
{
@@ -24,7 +25,7 @@ namespace Barotrauma
public ChildObject(XElement element)
{
AllowedNames = element.GetAttributeStringArray("names", new string[0]).ToList();
AllowedNames = element.GetAttributeStringArray("names", Array.Empty<string>()).ToList();
MinCount = element.GetAttributeInt("mincount", 1);
MaxCount = Math.Max(element.GetAttributeInt("maxcount", 1), MinCount);
}
@@ -58,13 +59,13 @@ namespace Barotrauma
private set;
}
[Serialize(1.0f, false), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
[Serialize(1.0f, IsPropertySaveable.No), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
public float MinSize
{
get;
private set;
}
[Serialize(1.0f, false), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
[Serialize(1.0f, IsPropertySaveable.No), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
public float MaxSize
{
get;
@@ -74,14 +75,14 @@ namespace Barotrauma
/// <summary>
/// Which sides of a wall the object can appear on.
/// </summary>
[Serialize((Alignment.Top | Alignment.Bottom | Alignment.Left | Alignment.Right), true, description: "Which sides of a wall the object can spawn on."), Editable]
[Serialize((Alignment.Top | Alignment.Bottom | Alignment.Left | Alignment.Right), IsPropertySaveable.Yes, description: "Which sides of a wall the object can spawn on."), Editable]
public Alignment Alignment
{
get;
private set;
}
[Serialize(SpawnPosType.Wall, false), Editable()]
[Serialize(SpawnPosType.Wall, IsPropertySaveable.No), Editable()]
public SpawnPosType SpawnPos
{
get;
@@ -94,13 +95,13 @@ namespace Barotrauma
private set;
}
public readonly List<XElement> LevelTriggerElements;
public readonly List<ContentXElement> LevelTriggerElements;
/// <summary>
/// Overrides the commonness of the object in a specific level type.
/// Key = name of the level type, value = commonness in that level type.
/// </summary>
public Dictionary<string, float> OverrideCommonness;
public readonly Dictionary<Identifier, float> OverrideCommonness;
public XElement PhysicsBodyElement
{
@@ -120,14 +121,14 @@ namespace Barotrauma
} = new Dictionary<Sprite, XElement>();
[Serialize(10000, false, description: "Maximum number of this specific object per level."), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
[Serialize(10000, IsPropertySaveable.No, description: "Maximum number of this specific object per level."), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
public int MaxCount
{
get;
private set;
}
[Serialize("0.0,1.0", true), Editable]
[Serialize("0.0,1.0", IsPropertySaveable.Yes), Editable]
public Vector2 DepthRange
{
get;
@@ -135,7 +136,7 @@ namespace Barotrauma
}
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f),
Serialize(0.0f, true, description: "The tendency for the prefab to form clusters. Used as an exponent for perlin noise values that are used to determine the probability for an object to spawn at a specific position.")]
Serialize(0.0f, IsPropertySaveable.Yes, description: "The tendency for the prefab to form clusters. Used as an exponent for perlin noise values that are used to determine the probability for an object to spawn at a specific position.")]
/// <summary>
/// The tendency for the prefab to form clusters. Used as an exponent for perlin noise values
/// that are used to determine the probability for an object to spawn at a specific position.
@@ -147,7 +148,7 @@ namespace Barotrauma
}
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f),
Serialize(0.0f, true, description: "A value between 0-1 that determines the z-coordinate to sample perlin noise from when determining the probability " +
Serialize(0.0f, IsPropertySaveable.Yes, description: "A value between 0-1 that determines the z-coordinate to sample perlin noise from when determining the probability " +
" for an object to spawn at a specific position. Using the same (or close) value for different objects means the objects tend " +
"to form clusters in the same areas.")]
/// <summary>
@@ -162,35 +163,35 @@ namespace Barotrauma
private set;
}
[Editable, Serialize("0,0", true, description: "Random offset from the surface the object spawns on.")]
[Editable, Serialize("0,0", IsPropertySaveable.Yes, description: "Random offset from the surface the object spawns on.")]
public Vector2 RandomOffset
{
get;
private set;
}
[Editable, Serialize(false, true, description: "Should the object be rotated to align it with the wall surface it spawns on.")]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Should the object be rotated to align it with the wall surface it spawns on.")]
public bool AlignWithSurface
{
get;
private set;
}
[Editable, Serialize(true, true, description: "Can the object be placed near the start of the level.")]
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the object be placed near the start of the level.")]
public bool AllowAtStart
{
get;
private set;
}
[Editable, Serialize(true, true, description: "Can the object be placed near the end of the level.")]
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the object be placed near the end of the level.")]
public bool AllowAtEnd
{
get;
private set;
}
[Serialize(0.0f, true, description: "Minimum length of a graph edge the object can spawn on."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
[Serialize(0.0f, IsPropertySaveable.Yes, description: "Minimum length of a graph edge the object can spawn on."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
/// <summary>
/// Minimum length of a graph edge the object can spawn on.
/// </summary>
@@ -201,7 +202,7 @@ namespace Barotrauma
}
private Vector2 randomRotation;
[Editable, Serialize("0.0,0.0", true, description: "How much the rotation of the object can vary (min and max values in degrees).")]
[Editable, Serialize("0.0,0.0", IsPropertySaveable.Yes, description: "How much the rotation of the object can vary (min and max values in degrees).")]
public Vector2 RandomRotation
{
get { return new Vector2(MathHelper.ToDegrees(randomRotation.X), MathHelper.ToDegrees(randomRotation.Y)); }
@@ -214,7 +215,7 @@ namespace Barotrauma
public Vector2 RandomRotationRad => randomRotation;
private float swingAmount;
[Serialize(0.0f, true, description: "How much the object swings (in degrees)."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 360.0f)]
[Serialize(0.0f, IsPropertySaveable.Yes, description: "How much the object swings (in degrees)."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 360.0f)]
public float SwingAmount
{
get { return MathHelper.ToDegrees(swingAmount); }
@@ -226,28 +227,28 @@ namespace Barotrauma
public float SwingAmountRad => swingAmount;
[Serialize(0.0f, true, description: "How fast the object swings."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
[Serialize(0.0f, IsPropertySaveable.Yes, description: "How fast the object swings."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float SwingFrequency
{
get;
private set;
}
[Editable, Serialize("0.0,0.0", true, description: "How much the scale of the object oscillates on each axis. A value of 0.5,0.5 would make the object's scale oscillate from 100% to 150%.")]
[Editable, Serialize("0.0,0.0", IsPropertySaveable.Yes, description: "How much the scale of the object oscillates on each axis. A value of 0.5,0.5 would make the object's scale oscillate from 100% to 150%.")]
public Vector2 ScaleOscillation
{
get;
private set;
}
[Serialize(0.0f, true, description: "How fast the object's scale oscillates."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
[Serialize(0.0f, IsPropertySaveable.Yes, description: "How fast the object's scale oscillates."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float ScaleOscillationFrequency
{
get;
private set;
}
[Editable, Serialize(1.0f, true, description: "How likely it is for the object to spawn in a level. " +
[Editable, Serialize(1.0f, IsPropertySaveable.Yes, description: "How likely it is for the object to spawn in a level. " +
"This is relative to the commonness of the other objects - for example, having an object with " +
"a commonness of 1 and another with a commonness of 10 would mean the latter appears in levels 10 times as frequently as the former. " +
"The commonness value can be overridden on specific level types.")]
@@ -257,45 +258,35 @@ namespace Barotrauma
private set;
}
[Serialize(0.0f, true, description: "How much the object disrupts submarine's sonar."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
[Serialize(0.0f, IsPropertySaveable.Yes, description: "How much the object disrupts submarine's sonar."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float SonarDisruption
{
get;
private set;
}
[Serialize(false, true, description: "Can the object take damage from weapons/attacks that damage level walls."), Editable]
[Serialize(false, IsPropertySaveable.Yes, description: "Can the object take damage from weapons/attacks that damage level walls."), Editable]
public bool TakeLevelWallDamage
{
get;
private set;
}
[Serialize(false, true), Editable]
[Serialize(false, IsPropertySaveable.Yes), Editable]
public bool HideWhenBroken
{
get;
private set;
}
[Serialize(100.0f, true), Editable]
[Serialize(100.0f, IsPropertySaveable.Yes), Editable]
public float Health
{
get;
private set;
}
public string Identifier
{
get;
set;
}
public string Name
{
get { return Identifier; }
}
public string Name => Identifier.Value;
public List<ChildObject> ChildObjects
{
@@ -303,7 +294,7 @@ namespace Barotrauma
private set;
}
public Dictionary<string, SerializableProperty> SerializableProperties
public Dictionary<Identifier, SerializableProperty> SerializableProperties
{
get; private set;
}
@@ -323,91 +314,20 @@ namespace Barotrauma
return "LevelObjectPrefab (" + Identifier + ")";
}
public static void LoadAll()
{
List.Clear();
var files = GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs);
if (files.Count() > 0)
{
foreach (var file in files)
{
LoadConfig(file.Path);
}
}
else
{
LoadConfig("Content/LevelObjects/LevelObject/Prefabs.xml");
}
}
private static void LoadConfig(string configPath)
{
try
{
XDocument doc = XMLExtensions.TryLoadXml(configPath);
if (doc == null) { return; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
mainElement = doc.Root.FirstElement();
DebugConsole.NewMessage($"Overriding all level object prefabs with '{configPath}'", Color.Yellow);
List.Clear();
}
else if (List.Any())
{
DebugConsole.Log($"Loading additional level object prefabs from file '{configPath}'");
}
foreach (XElement subElement in mainElement.Elements())
{
var element = subElement.IsOverride() ? subElement.FirstElement() : subElement;
string identifier = element.GetAttributeString("identifier", "");
var existingPrefab = List.Find(p => p.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
if (existingPrefab != null)
{
if (subElement.IsOverride())
{
DebugConsole.NewMessage($"Overriding the existing level object prefab '{identifier}' using the file '{configPath}'", Color.Yellow);
List.Remove(existingPrefab);
}
else
{
DebugConsole.ThrowError($"Error in '{configPath}': Duplicate level object prefab '{identifier}' found in '{configPath}'! Each level object prefab must have a unique identifier. " +
"Use <override></override> tags to override prefabs.");
continue;
}
}
List.Add(new LevelObjectPrefab(element));
}
}
catch (Exception e)
{
DebugConsole.ThrowError(string.Format("Failed to load LevelObject prefabs from {0}", configPath), e);
}
}
public LevelObjectPrefab(XElement element, string identifier = null)
public LevelObjectPrefab(ContentXElement element, LevelObjectPrefabsFile file, Identifier identifierOverride = default) : base(file, ParseIdentifier(identifierOverride, element))
{
ChildObjects = new List<ChildObject>();
LevelTriggerElements = new List<XElement>();
LevelTriggerElements = new List<ContentXElement>();
OverrideProperties = new List<LevelObjectPrefab>();
OverrideCommonness = new Dictionary<string, float>();
OverrideCommonness = new Dictionary<Identifier, float>();
Identifier = null;
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
if (element != null)
{
Config = element;
Identifier = element.GetAttributeString("identifier", null) ?? identifier;
if (string.IsNullOrEmpty(Identifier))
{
#if DEBUG
DebugConsole.ThrowError($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
#else
DebugConsole.AddWarning($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
#endif
Identifier = element.Name.ToString();
}
LoadElements(element, -1);
LoadElements(file, element, -1);
InitProjSpecific(element);
}
@@ -419,10 +339,26 @@ namespace Barotrauma
}
}
private void LoadElements(XElement element, int parentTriggerIndex)
public static Identifier ParseIdentifier(Identifier identifierOverride, XElement element)
{
if (!identifierOverride.IsEmpty) { return identifierOverride; }
Identifier identifier = element.GetAttributeIdentifier("identifier", "");
if (identifier.IsEmpty)
{
#if DEBUG
DebugConsole.ThrowError($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
#else
DebugConsole.AddWarning($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
#endif
identifier = element.NameAsIdentifier();
}
return identifier;
}
private void LoadElements(LevelObjectPrefabsFile file, ContentXElement element, int parentTriggerIndex)
{
int propertyOverrideCount = 0;
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -430,8 +366,8 @@ namespace Barotrauma
var newSprite = new Sprite(subElement, lazyLoad: true);
Sprites.Add(newSprite);
var spriteSpecificPhysicsBodyElement =
subElement.Element("PhysicsBody") ?? subElement.Element("Body") ??
subElement.Element("physicsbody") ?? subElement.Element("body");
subElement.GetChildElement("PhysicsBody") ?? subElement.GetChildElement("Body") ??
subElement.GetChildElement("physicsbody") ?? subElement.GetChildElement("body");
if (spriteSpecificPhysicsBodyElement != null)
{
SpriteSpecificPhysicsBodyElements.Add(newSprite, spriteSpecificPhysicsBodyElement);
@@ -441,7 +377,7 @@ namespace Barotrauma
DeformableSprite = new DeformableSprite(subElement, lazyLoad: true);
break;
case "overridecommonness":
string levelType = subElement.GetAttributeString("leveltype", "").ToLowerInvariant();
Identifier levelType = subElement.GetAttributeIdentifier("leveltype", Identifier.Empty);
if (!OverrideCommonness.ContainsKey(levelType))
{
OverrideCommonness.Add(levelType, subElement.GetAttributeFloat("commonness", 1.0f));
@@ -451,13 +387,13 @@ namespace Barotrauma
case "trigger":
OverrideProperties.Add(null);
LevelTriggerElements.Add(subElement);
LoadElements(subElement, LevelTriggerElements.Count - 1);
LoadElements(file, subElement, LevelTriggerElements.Count - 1);
break;
case "childobject":
ChildObjects.Add(new ChildObject(subElement));
break;
case "overrideproperties":
var propertyOverride = new LevelObjectPrefab(subElement, identifier: Identifier + "-" + propertyOverrideCount);
var propertyOverride = new LevelObjectPrefab(subElement, file, identifierOverride: $"{Identifier}-{propertyOverrideCount}".ToIdentifier());
OverrideProperties[OverrideProperties.Count - 1] = propertyOverride;
if (!propertyOverride.Sprites.Any() && propertyOverride.DeformableSprite == null)
{
@@ -475,12 +411,13 @@ namespace Barotrauma
}
}
partial void InitProjSpecific(XElement element);
partial void InitProjSpecific(ContentXElement element);
public float GetCommonness(CaveGenerationParams generationParams, bool requireCaveSpecificOverride = true)
{
if (generationParams?.Identifier != null &&
if (generationParams != null &&
generationParams.Identifier != Identifier.Empty &&
OverrideCommonness.TryGetValue(generationParams.Identifier, out float commonness))
{
return commonness;
@@ -490,13 +427,16 @@ namespace Barotrauma
public float GetCommonness(LevelGenerationParams generationParams)
{
if (generationParams?.Identifier != null &&
if (generationParams != null &&
generationParams.Identifier != Identifier.Empty &&
(OverrideCommonness.TryGetValue(generationParams.Identifier, out float commonness) ||
(generationParams.OldIdentifier != null && OverrideCommonness.TryGetValue(generationParams.OldIdentifier, out commonness))))
(!generationParams.OldIdentifier.IsEmpty && OverrideCommonness.TryGetValue(generationParams.OldIdentifier, out commonness))))
{
return commonness;
}
return Commonness;
}
public override void Dispose() { }
}
}
@@ -184,7 +184,7 @@ namespace Barotrauma
set;
}
public string InfectIdentifier
public Identifier InfectIdentifier
{
get;
set;
@@ -199,7 +199,7 @@ namespace Barotrauma
private bool triggeredOnce;
private readonly bool triggerOnce;
public LevelTrigger(XElement element, Vector2 position, float rotation, float scale = 1.0f, string parentDebugName = "")
public LevelTrigger(ContentXElement element, Vector2 position, float rotation, float scale = 1.0f, string parentDebugName = "")
{
TriggererPosition = new Dictionary<Entity, Vector2>();
@@ -223,7 +223,7 @@ namespace Barotrauma
cameraShake = element.GetAttributeFloat("camerashake", 0.0f);
InfectIdentifier = element.GetAttributeString("infectidentifier", null);
InfectIdentifier = element.GetAttributeIdentifier("infectidentifier", Identifier.Empty);
InfectionChance = element.GetAttributeFloat("infectionchance", 0.05f);
triggerOnce = element.GetAttributeBool("triggeronce", false);
@@ -264,7 +264,7 @@ namespace Barotrauma
TriggerOthersDistance = element.GetAttributeFloat("triggerothersdistance", 0.0f);
var tagsArray = element.GetAttributeStringArray("tags", new string[0]);
var tagsArray = element.GetAttributeStringArray("tags", Array.Empty<string>());
foreach (string tag in tagsArray)
{
tags.Add(tag.ToLowerInvariant());
@@ -272,7 +272,7 @@ namespace Barotrauma
if (triggeredBy.HasFlag(TriggererType.OtherTrigger))
{
var otherTagsArray = element.GetAttributeStringArray("allowedothertriggertags", new string[0]);
var otherTagsArray = element.GetAttributeStringArray("allowedothertriggertags", Array.Empty<string>());
foreach (string tag in otherTagsArray)
{
allowedOtherTriggerTags.Add(tag.ToLowerInvariant());
@@ -280,7 +280,7 @@ namespace Barotrauma
}
string debugName = string.IsNullOrEmpty(parentDebugName) ? "LevelTrigger" : $"LevelTrigger in {parentDebugName}";
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -317,12 +317,12 @@ namespace Barotrauma
-sa * unrotatedForce.X + ca * unrotatedForce.Y);
}
public static void LoadStatusEffect(List<StatusEffect> statusEffects, XElement element, string parentDebugName)
public static void LoadStatusEffect(List<StatusEffect> statusEffects, ContentXElement element, string parentDebugName)
{
statusEffects.Add(StatusEffect.Load(element, parentDebugName));
}
public static void LoadAttack(XElement element, string parentDebugName, bool triggerOnce, List<Attack> attacks)
public static void LoadAttack(ContentXElement element, string parentDebugName, bool triggerOnce, List<Attack> attacks)
{
var attack = new Attack(element, parentDebugName);
if (!triggerOnce)
@@ -574,7 +574,7 @@ namespace Barotrauma
else if (triggerer is Submarine submarine)
{
ApplyAttacks(attacks, worldPosition, deltaTime);
if (!string.IsNullOrWhiteSpace(InfectIdentifier))
if (!InfectIdentifier.IsEmpty)
{
submarine.AttemptBallastFloraInfection(InfectIdentifier, deltaTime, InfectionChance);
}