Unstable 0.17.0.0
This commit is contained in:
+67
-127
@@ -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() { }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user