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
@@ -0,0 +1,113 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class AfflictionsFile : ContentFile
{
private readonly static ImmutableHashSet<Type> afflictionTypes;
static AfflictionsFile()
{
afflictionTypes = ReflectionUtils.GetDerivedNonAbstract<Affliction>()
.ToImmutableHashSet();
}
public AfflictionsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
private void ParseElement(ContentXElement element, bool overriding)
{
Identifier elementName = element.NameAsIdentifier();
if (element.IsOverride())
{
element.Elements().ForEach(s => ParseElement(s, overriding: true));
}
else if (elementName == "Afflictions")
{
element.Elements().ForEach(s => ParseElement(s, overriding: overriding));
}
else if (elementName == "cprsettings")
{
var cprSettings = new CPRSettings(element, this);
CPRSettings.Prefabs.Add(cprSettings, overriding);
}
else if (elementName == "damageoverlay")
{
#if CLIENT
var damageOverlay = new CharacterHealth.DamageOverlayPrefab(element, this);
CharacterHealth.DamageOverlayPrefab.Prefabs.Add(damageOverlay, overriding);
#endif
}
else
{
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
if (identifier.IsEmpty)
{
DebugConsole.ThrowError(
$"No identifier defined for the affliction '{elementName}' in file '{Path}'");
return;
}
if (AfflictionPrefab.Prefabs.ContainsKey(identifier))
{
if (overriding)
{
DebugConsole.NewMessage(
$"Overriding an affliction or a buff with the identifier '{identifier}' using the file '{Path}'",
Color.Yellow);
}
else
{
DebugConsole.ThrowError(
$"Duplicate affliction: '{identifier}' defined in {elementName} of '{Path}'");
return;
}
}
var type = afflictionTypes.FirstOrDefault(t =>
t.Name == elementName
|| t.Name == $"Affliction{elementName}".ToIdentifier())
?? typeof(Affliction);
var prefab = CreatePrefab(element, type);
AfflictionPrefab.Prefabs.Add(prefab, overriding);
}
}
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc?.Root is null) { return; }
ParseElement(doc.Root.FromPackage(ContentPackage), overriding: false);
}
private AfflictionPrefab CreatePrefab(ContentXElement element, Type type)
{
if (type == typeof(AfflictionHusk)) { return new AfflictionPrefabHusk(element, this, type); }
return new AfflictionPrefab(element, this, type);
}
public override void UnloadFile()
{
#if CLIENT
CharacterHealth.DamageOverlayPrefab.Prefabs.RemoveByFile(this);
#endif
CPRSettings.Prefabs.RemoveByFile(this);
AfflictionPrefab.Prefabs.RemoveByFile(this);
}
public override void Sort()
{
#if CLIENT
CharacterHealth.DamageOverlayPrefab.Prefabs.Sort();
#endif
CPRSettings.Prefabs.Sort();
AfflictionPrefab.Prefabs.SortAll();
}
}
}
@@ -0,0 +1,9 @@
namespace Barotrauma
{
sealed class BackgroundCreaturePrefabsFile : OtherFile
{
public BackgroundCreaturePrefabsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
//this content type only comes into play when a level is generated, so LoadFile and UnloadFile don't have anything to do
}
}
@@ -0,0 +1,19 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage, AlternativeContentTypeNames("MapCreature")]
sealed class BallastFloraFile : GenericPrefabFile<BallastFloraPrefab>
{
public BallastFloraFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "ballastflorabehavior";
protected override bool MatchesPlural(Identifier identifier) => identifier == "ballastflorabehaviors";
protected override PrefabCollection<BallastFloraPrefab> prefabs => BallastFloraPrefab.Prefabs;
protected override BallastFloraPrefab CreatePrefab(ContentXElement element)
{
return new BallastFloraPrefab(element, this);
}
}
}
@@ -0,0 +1,8 @@
namespace Barotrauma
{
[RequiredByCorePackage]
public class BeaconStationFile : BaseSubFile
{
public BeaconStationFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class CaveGenerationParametersFile : GenericPrefabFile<CaveGenerationParams>
{
public CaveGenerationParametersFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "cave";
protected override bool MatchesPlural(Identifier identifier) => identifier == "cavegenerationparameters";
protected override PrefabCollection<CaveGenerationParams> prefabs => CaveGenerationParams.CaveParams;
protected override CaveGenerationParams CreatePrefab(ContentXElement element)
{
return new CaveGenerationParams(element, this);
}
}
}
@@ -0,0 +1,100 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class CharacterFile : ContentFile
{
public CharacterFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null)
{
DebugConsole.ThrowError($"Loading character file failed: {Path}");
return;
}
if (CharacterPrefab.Prefabs.AllPrefabs.Any(kvp => kvp.Value.Any(cf => cf?.ContentFile == this)))
{
DebugConsole.ThrowError($"Duplicate path: {Path}");
return;
}
var mainElement = doc.Root.FromPackage(ContentPackage);
bool isOverride = mainElement.IsOverride();
if (isOverride) { mainElement = mainElement.FirstElement(); }
if (!CharacterPrefab.CheckSpeciesName(mainElement, this, out Identifier n)) { return; }
var prefab = new CharacterPrefab(mainElement, this);
CharacterPrefab.Prefabs.Add(prefab, isOverride);
}
public override void UnloadFile()
{
CharacterPrefab.Prefabs.RemoveByFile(this);
}
public override void Sort()
{
CharacterPrefab.Prefabs.SortAll();
}
public override void Preload(Action<Sprite> addPreloadedSprite)
{
#if CLIENT
CharacterPrefab characterPrefab = CharacterPrefab.FindByFilePath(Path.Value);
if (characterPrefab?.ConfigElement == null)
{
throw new Exception($"Failed to load the character config file from {Path}!");
}
var mainElement = characterPrefab.ConfigElement;
mainElement.GetChildElements("sound").ForEach(e => RoundSound.Load(e));
if (!CharacterPrefab.CheckSpeciesName(mainElement, this, out Identifier speciesName)) { return; }
bool humanoid = mainElement.GetAttributeBool("humanoid", false);
RagdollParams ragdollParams;
try
{
if (humanoid)
{
ragdollParams = RagdollParams.GetRagdollParams<HumanRagdollParams>(speciesName);
}
else
{
ragdollParams = RagdollParams.GetRagdollParams<FishRagdollParams>(speciesName);
}
}
catch (Exception e)
{
DebugConsole.ThrowError($"Failed to preload a ragdoll file for the character \"{characterPrefab.Name}\"", e);
return;
}
if (ragdollParams != null)
{
HashSet<string> texturePaths = new HashSet<string>
{
ragdollParams.Texture
};
foreach (RagdollParams.LimbParams limb in ragdollParams.Limbs)
{
if (!string.IsNullOrEmpty(limb.normalSpriteParams?.Texture)) { texturePaths.Add(limb.normalSpriteParams.Texture); }
if (!string.IsNullOrEmpty(limb.deformSpriteParams?.Texture)) { texturePaths.Add(limb.deformSpriteParams.Texture); }
if (!string.IsNullOrEmpty(limb.damagedSpriteParams?.Texture)) { texturePaths.Add(limb.damagedSpriteParams.Texture); }
foreach (var decorativeSprite in limb.decorativeSpriteParams)
{
if (!string.IsNullOrEmpty(decorativeSprite.Texture)) { texturePaths.Add(decorativeSprite.Texture); }
}
}
foreach (string texturePath in texturePaths)
{
addPreloadedSprite(new Sprite(texturePath, Vector2.Zero));
}
}
#endif
}
}
}
@@ -0,0 +1,117 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class NotSyncedInMultiplayer : Attribute { }
/// <summary>
/// Base class for content file types, which are loaded
/// from filelist.xml via reflection.
/// PLEASE AVOID INHERITING FROM THIS CLASS DIRECTLY.
/// Inheriting from GenericPrefabFile&lt;T&gt; is likely what
/// you want.
/// </summary>
public abstract class ContentFile
{
public class TypeInfo
{
public readonly Type Type;
public readonly bool RequiredByCorePackage;
public readonly bool NotSyncedInMultiplayer;
public readonly ImmutableHashSet<Type>? AlternativeTypes;
public readonly ImmutableHashSet<Identifier> Names;
public TypeInfo(Type type)
{
Type = type;
var reqByCoreAttribute = type.GetCustomAttribute<RequiredByCorePackage>();
RequiredByCorePackage = reqByCoreAttribute != null;
var notSyncedInMultiplayerAttribute = type.GetCustomAttribute<NotSyncedInMultiplayer>();
NotSyncedInMultiplayer = notSyncedInMultiplayerAttribute != null;
AlternativeTypes = reqByCoreAttribute?.AlternativeTypes;
HashSet<Identifier> names = new HashSet<Identifier> { type.Name.RemoveFromEnd("File").ToIdentifier() };
if (type.GetCustomAttribute<AlternativeContentTypeNames>()?.Names is { } altNames)
{
names.UnionWith(altNames);
}
Names = names.ToImmutableHashSet();
}
public ContentFile? CreateInstance(ContentPackage contentPackage, ContentPath path) =>
(ContentFile?)Activator.CreateInstance(Type, contentPackage, path);
}
public readonly static ImmutableHashSet<TypeInfo> Types;
static ContentFile()
{
Types = ReflectionUtils.GetDerivedNonAbstract<ContentFile>()
.Select(t => new TypeInfo(t))
.ToImmutableHashSet();
}
public static Result<ContentFile, string> CreateFromXElement(ContentPackage contentPackage, XElement element)
{
Result<ContentFile, string> fail(string error)
=> Result<ContentFile, string>.Failure(error);
Identifier elemName = element.NameAsIdentifier();
var type = Types.FirstOrDefault(t => t.Names.Contains(elemName));
var filePath = element.GetAttributeContentPath("file", contentPackage);
if (type is null)
{
return fail($"Invalid content type \"{elemName}\"");
}
if (filePath is null)
{
return fail($"No content path defined for file of type \"{elemName}\"");
}
try
{
var file = type.CreateInstance(contentPackage, filePath);
return file is null
? throw new Exception($"Content type is not implemented correctly")
: Result<ContentFile, string>.Success(file);
}
catch (Exception e)
{
return fail($"Failed to load file \"{filePath}\" of type \"{elemName}\": {e.Message}\n{e.StackTrace.CleanupStackTrace()}");
}
}
protected ContentFile(ContentPackage contentPackage, ContentPath path)
{
ContentPackage = contentPackage;
Path = path;
Hash = CalculateHash();
}
public readonly ContentPackage ContentPackage;
public readonly ContentPath Path;
public readonly Md5Hash Hash;
public abstract void LoadFile();
public abstract void UnloadFile();
public abstract void Sort();
public virtual void Preload(Action<Sprite> addPreloadedSprite) { }
public virtual Md5Hash CalculateHash()
{
return Md5Hash.CalculateForFile(Path.Value, Md5Hash.StringHashOptions.IgnoreWhitespace);
}
public bool NotSyncedInMultiplayer => Types.Any(t => t.Type == GetType() && t.NotSyncedInMultiplayer);
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class CorpsesFile : GenericPrefabFile<CorpsePrefab>
{
public CorpsesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "corpse";
protected override bool MatchesPlural(Identifier identifier) => identifier == "corpses";
protected override PrefabCollection<CorpsePrefab> prefabs => CorpsePrefab.Prefabs;
protected override CorpsePrefab CreatePrefab(ContentXElement element)
{
return new CorpsePrefab(element, this);
}
}
}
@@ -0,0 +1,22 @@
namespace Barotrauma
{
public sealed class DecalsFile : ContentFile
{
public DecalsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
DecalManager.LoadFromFile(this);
}
public override void UnloadFile()
{
DecalManager.RemoveByFile(this);
}
public override void Sort()
{
DecalManager.SortAll();
}
}
}
@@ -0,0 +1,8 @@
namespace Barotrauma
{
[RequiredByCorePackage]
public class EnemySubmarineFile : BaseSubFile
{
public EnemySubmarineFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}
@@ -0,0 +1,17 @@
using System.Xml.Linq;
namespace Barotrauma
{
sealed class EventManagerSettingsFile : GenericPrefabFile<EventManagerSettings>
{
public EventManagerSettingsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "EventManagerSettings";
protected override PrefabCollection<EventManagerSettings> prefabs => EventManagerSettings.Prefabs;
protected override EventManagerSettings CreatePrefab(ContentXElement element)
{
return new EventManagerSettings(element, this);
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class FactionsFile : GenericPrefabFile<FactionPrefab>
{
public FactionsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "faction";
protected override bool MatchesPlural(Identifier identifier) => identifier == "factions";
protected override PrefabCollection<FactionPrefab> prefabs => FactionPrefab.Prefabs;
protected override FactionPrefab CreatePrefab(ContentXElement element)
{
return new FactionPrefab(element, this);
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
abstract class GenericPrefabFile<T> : ContentFile where T : Prefab
{
protected GenericPrefabFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected abstract bool MatchesSingular(Identifier identifier);
protected abstract bool MatchesPlural(Identifier identifier);
protected abstract PrefabCollection<T> prefabs { get; }
protected abstract T CreatePrefab(ContentXElement element);
private void LoadFromXElement(ContentXElement parentElement, bool overriding)
{
Identifier elemName = parentElement.NameAsIdentifier();
var childElements = parentElement.Elements()
#if DEBUG
.OrderBy(e => Rand.Int(int.MaxValue, Rand.RandSync.Unsynced)).ToArray()
#endif
;
if (parentElement.IsOverride())
{
foreach (var element in childElements)
{
LoadFromXElement(element, true);
}
}
else if (elemName == "clear")
{
prefabs.AddOverrideFile(this);
}
else if (MatchesSingular(elemName))
{
T prefab = CreatePrefab(parentElement);
prefabs.Add(prefab, overriding);
}
else if (MatchesPlural(elemName))
{
foreach (var element in childElements)
{
LoadFromXElement(element, overriding);
}
}
else
{
DebugConsole.ThrowError($"Invalid {GetType().Name} element: {parentElement.Name} in {Path}");
}
}
public override sealed void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var rootElement = doc.Root.FromPackage(ContentPackage);
LoadFromXElement(rootElement, false);
}
public override sealed void UnloadFile()
{
prefabs.RemoveByFile(this);
}
public sealed override void Sort()
{
prefabs.SortAll();
}
}
}
@@ -0,0 +1,10 @@
namespace Barotrauma
{
[NotSyncedInMultiplayer]
public abstract class HashlessFile : ContentFile
{
public HashlessFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public sealed override Md5Hash CalculateHash() => Md5Hash.Blank;
}
}
@@ -0,0 +1,17 @@
using System.Xml.Linq;
namespace Barotrauma
{
sealed class ItemAssemblyFile : GenericPrefabFile<ItemAssemblyPrefab>
{
public ItemAssemblyFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "itemassembly";
protected override bool MatchesPlural(Identifier identifier) => identifier == "itemassemblies";
protected override PrefabCollection<ItemAssemblyPrefab> prefabs => ItemAssemblyPrefab.Prefabs;
protected override ItemAssemblyPrefab CreatePrefab(ContentXElement element)
{
return new ItemAssemblyPrefab(element, this);
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class ItemFile : GenericPrefabFile<ItemPrefab>
{
public ItemFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "items";
protected override PrefabCollection<ItemPrefab> prefabs => ItemPrefab.Prefabs;
protected override ItemPrefab CreatePrefab(ContentXElement element)
{
return new ItemPrefab(element, this);
}
}
}
@@ -0,0 +1,60 @@
using Barotrauma;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class JobsFile : ContentFile
{
public JobsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
LoadElements(doc.Root.FromPackage(ContentPackage), false);
}
private void LoadElements(ContentXElement mainElement, bool isOverride)
{
foreach (var element in mainElement.Elements())
{
if (element.NameAsIdentifier() == "nojob")
{
JobPrefab.NoJobElement ??= element;
}
else if (element.NameAsIdentifier() == "ItemRepairPriorities")
{
foreach (var subElement in element.Elements())
{
ItemRepairPriority prio = new ItemRepairPriority(subElement, this);
ItemRepairPriority.Prefabs.Add(prio, isOverride);
}
}
else if (element.IsOverride())
{
LoadElements(element, true);
}
else
{
var job = new JobPrefab(element, this);
JobPrefab.Prefabs.Add(job, isOverride);
}
}
}
public override void UnloadFile()
{
JobPrefab.Prefabs.RemoveByFile(this);
ItemRepairPriority.Prefabs.RemoveByFile(this);
}
public override void Sort()
{
JobPrefab.Prefabs.SortAll();
}
}
}
@@ -0,0 +1,68 @@
using System;
using System.Xml.Linq;
namespace Barotrauma
{
sealed class LevelGenerationParametersFile : ContentFile
{
public LevelGenerationParametersFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
private void LoadBiomes(ContentXElement element, bool isOverride)
{
foreach (var subElement in element.Elements())
{
Biome biome = new Biome(subElement, this);
Biome.Prefabs.Add(biome, isOverride);
}
}
private void LoadLevelGenerationParams(ContentXElement element, bool isOverride)
{
LevelGenerationParams lParams = new LevelGenerationParams(element, this);
LevelGenerationParams.LevelParams.Add(lParams, isOverride);
}
private void LoadSubElements(ContentXElement element, bool overridePropagation)
{
foreach (var subElement in element.Elements())
{
if (subElement.IsOverride())
{
LoadSubElements(subElement, true);
}
else if (subElement.NameAsIdentifier() == "clear")
{
LevelGenerationParams.LevelParams.AddOverrideFile(this);
Biome.Prefabs.AddOverrideFile(this);
}
else if (subElement.NameAsIdentifier() == "biomes")
{
LoadBiomes(subElement, overridePropagation);
}
else
{
LoadLevelGenerationParams(subElement, overridePropagation);
}
}
}
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc is null) { return; }
LoadSubElements(doc.Root.FromPackage(ContentPackage), false);
}
public override void UnloadFile()
{
LevelGenerationParams.LevelParams.RemoveByFile(this);
Biome.Prefabs.RemoveByFile(this);
}
public override void Sort()
{
LevelGenerationParams.LevelParams.SortAll();
Biome.Prefabs.SortAll();
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class LevelObjectPrefabsFile : GenericPrefabFile<LevelObjectPrefab>
{
public LevelObjectPrefabsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "levelobjects";
protected override PrefabCollection<LevelObjectPrefab> prefabs => LevelObjectPrefab.Prefabs;
protected override LevelObjectPrefab CreatePrefab(ContentXElement element)
{
return new LevelObjectPrefab(element, this);
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class LocationTypesFile : GenericPrefabFile<LocationType>
{
public LocationTypesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "locationtypes";
protected override PrefabCollection<LocationType> prefabs => LocationType.Prefabs;
protected override LocationType CreatePrefab(ContentXElement element)
{
return new LocationType(element, this);
}
}
}
@@ -0,0 +1,34 @@
using System.Xml.Linq;
namespace Barotrauma
{
sealed class MapGenerationParametersFile : ContentFile
{
public MapGenerationParametersFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null)
{
DebugConsole.ThrowError($"Loading map generation parameters file failed: {Path}");
return;
}
var mainElement = doc.Root.FromPackage(ContentPackage);
bool isOverride = mainElement.IsOverride();
if (isOverride) { mainElement = mainElement.FirstElement(); }
var prefab = new MapGenerationParams(mainElement, this);
MapGenerationParams.Params.Add(prefab, isOverride);
}
public override void UnloadFile()
{
MapGenerationParams.Params.RemoveByFile(this);
}
public override void Sort()
{
MapGenerationParams.Params.Sort();
}
}
}
@@ -0,0 +1,32 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class MissionsFile : GenericPrefabFile<MissionPrefab>
{
/*private readonly static ImmutableHashSet<Type> missionTypes;
static MissionsFile()
{
missionTypes = ReflectionUtils.GetDerivedNonAbstract<Mission>()
.ToImmutableHashSet();
}*/
public MissionsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier)
=> !MatchesPlural(identifier);
/*missionTypes.Any(t => identifier == t.Name)
|| identifier == "OutpostDestroyMission" || identifier == "OutpostRescueMission";*/
protected override bool MatchesPlural(Identifier identifier) => identifier == "missions";
protected override PrefabCollection<MissionPrefab> prefabs => MissionPrefab.Prefabs;
protected override MissionPrefab CreatePrefab(ContentXElement element)
{
return new MissionPrefab(element, this);
}
}
}
@@ -0,0 +1,44 @@
using System.Xml.Linq;
namespace Barotrauma
{
sealed class NPCConversationsFile : ContentFile
{
public NPCConversationsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var mainElement = doc.Root.FromPackage(ContentPackage);
bool allowOverriding = doc.Root.IsOverride();
if (allowOverriding)
{
mainElement = mainElement.FirstElement();
}
var npcConversationCollection = new NPCConversationCollection(this, mainElement);
if (!NPCConversationCollection.Collections.ContainsKey(npcConversationCollection.Language))
{
NPCConversationCollection.Collections.Add(npcConversationCollection.Language, new PrefabCollection<NPCConversationCollection>());
}
NPCConversationCollection.Collections[npcConversationCollection.Language].Add(npcConversationCollection, allowOverriding);
}
public override void UnloadFile()
{
foreach (var collection in NPCConversationCollection.Collections.Values)
{
collection.RemoveByFile(this);
}
}
public override void Sort()
{
foreach (var collection in NPCConversationCollection.Collections.Values)
{
collection.SortAll();
}
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class NPCSetsFile : GenericPrefabFile<NPCSet>
{
public NPCSetsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "npcset";
protected override bool MatchesPlural(Identifier identifier) => identifier == "npcsets";
protected override PrefabCollection<NPCSet> prefabs => NPCSet.Sets;
protected override NPCSet CreatePrefab(ContentXElement element)
{
return new NPCSet(element, this);
}
}
}
@@ -0,0 +1,70 @@
using System.Xml.Linq;
namespace Barotrauma
{
#warning TODO: this is almost a GenericPrefabFile. Must refactor further.
[RequiredByCorePackage]
sealed class OrdersFile : ContentFile
{
public OrdersFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public void LoadFromXElement(ContentXElement parentElement, bool overriding)
{
Identifier elemName = new Identifier(parentElement.Name.ToString());
if (parentElement.IsOverride())
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, true);
}
}
else if (elemName == "order")
{
OrderPrefab prefab = new OrderPrefab(parentElement, this);
OrderPrefab.Prefabs.Add(prefab, overriding);
}
else if (elemName == "ordercategory")
{
OrderCategoryIcon prefab = new OrderCategoryIcon(parentElement, this);
OrderCategoryIcon.OrderCategoryIcons.Add(prefab, overriding);
}
else if (elemName == "orders")
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, overriding);
}
}
else if (elemName == "clear")
{
OrderCategoryIcon.OrderCategoryIcons.AddOverrideFile(this);
OrderPrefab.Prefabs.AddOverrideFile(this);
}
else
{
DebugConsole.ThrowError($"Invalid {GetType().Name} element: {parentElement.Name} in {Path}");
}
}
public override sealed void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var rootElement = doc.Root.FromPackage(ContentPackage);
LoadFromXElement(rootElement, false);
}
public override sealed void UnloadFile()
{
OrderCategoryIcon.OrderCategoryIcons.RemoveByFile(this);
OrderPrefab.Prefabs.RemoveByFile(this);
}
public override sealed void Sort()
{
OrderCategoryIcon.OrderCategoryIcons.SortAll();
OrderPrefab.Prefabs.SortAll();
}
}
}
@@ -0,0 +1,16 @@
using Barotrauma;
namespace Barotrauma
{
[AlternativeContentTypeNames("None")]
public class OtherFile : HashlessFile
{
public OtherFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
//this content type is completely ignored by the game so LoadFile and UnloadFile don't do anything
public sealed override void LoadFile() { }
public sealed override void UnloadFile() { }
public sealed override void Sort() { }
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage(alternativeTypes: typeof(OutpostFile))]
sealed class OutpostConfigFile : GenericPrefabFile<OutpostGenerationParams>
{
public OutpostConfigFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "OutpostConfig";
protected override bool MatchesPlural(Identifier identifier) => identifier == "OutpostGenerationParameters";
protected override PrefabCollection<OutpostGenerationParams> prefabs => OutpostGenerationParams.OutpostParams;
protected override OutpostGenerationParams CreatePrefab(ContentXElement element)
{
return new OutpostGenerationParams(element, this);
}
}
}
@@ -0,0 +1,7 @@
namespace Barotrauma
{
public class OutpostFile : BaseSubFile
{
public OutpostFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}
@@ -0,0 +1,7 @@
namespace Barotrauma
{
public class OutpostModuleFile : BaseSubFile
{
public OutpostModuleFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}
@@ -0,0 +1,31 @@
using System.Xml.Linq;
#if CLIENT
using Barotrauma.Particles;
#endif
namespace Barotrauma
{
[RequiredByCorePackage]
[NotSyncedInMultiplayer]
#if CLIENT
sealed class ParticlesFile : GenericPrefabFile<ParticlePrefab>
{
public ParticlesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "prefabs" || identifier == "particles";
protected override PrefabCollection<ParticlePrefab> prefabs => ParticlePrefab.Prefabs;
protected override ParticlePrefab CreatePrefab(ContentXElement element)
{
return new ParticlePrefab(element, this);
}
public override Md5Hash CalculateHash() => Md5Hash.Blank;
}
#else
sealed class ParticlesFile : OtherFile
{
public ParticlesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { } //this content type doesn't do anything on a server
}
#endif
}
@@ -0,0 +1,91 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class RandomEventsFile : ContentFile
{
public RandomEventsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public void LoadFromXElement(ContentXElement parentElement, bool overriding)
{
Identifier elemName = new Identifier(parentElement.Name.ToString());
if (parentElement.IsOverride())
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, true);
}
}
else if (elemName == "randomevents")
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, overriding);
}
}
else if (elemName == "eventprefabs")
{
foreach (var subElement in parentElement.Elements())
{
var prefab = new EventPrefab(subElement, this);
EventPrefab.Prefabs.Add(prefab, overriding);
}
}
else if (elemName == "eventsprites")
{
#if CLIENT
foreach (var subElement in parentElement.Elements())
{
var prefab = new EventSprite(subElement, this);
EventSprite.Prefabs.Add(prefab, overriding);
}
#endif
}
else if (elemName == "eventset")
{
var prefab = new EventSet(parentElement, this);
EventSet.Prefabs.Add(prefab, overriding);
}
else if (elemName == "clear")
{
EventPrefab.Prefabs.AddOverrideFile(this);
EventSet.Prefabs.AddOverrideFile(this);
#if CLIENT
EventSprite.Prefabs.AddOverrideFile(this);
#endif
}
else
{
DebugConsole.ThrowError($"Invalid {GetType().Name} element: {parentElement.Name} in {Path}");
}
}
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var rootElement = doc.Root.FromPackage(ContentPackage);
LoadFromXElement(rootElement, false);
}
public override void UnloadFile()
{
EventPrefab.Prefabs.RemoveByFile(this);
EventSet.Prefabs.RemoveByFile(this);
#if CLIENT
EventSprite.Prefabs.RemoveByFile(this);
#endif
}
public override void Sort()
{
EventPrefab.Prefabs.SortAll();
EventSet.Prefabs.SortAll();
#if CLIENT
EventSprite.Prefabs.SortAll();
#endif
}
}
}
@@ -0,0 +1,19 @@
using Barotrauma.RuinGeneration;
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class RuinConfigFile : GenericPrefabFile<RuinGenerationParams>
{
public RuinConfigFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "RuinConfig";
protected override bool MatchesPlural(Identifier identifier) => identifier == "RuinGenerationParameters";
protected override PrefabCollection<RuinGenerationParams> prefabs => RuinGenerationParams.RuinParams;
protected override RuinGenerationParams CreatePrefab(ContentXElement element)
{
return new RuinGenerationParams(element, this);
}
}
}
@@ -0,0 +1,33 @@
using System.Xml.Linq;
namespace Barotrauma
{
sealed class SkillSettingsFile : ContentFile
{
public SkillSettingsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var mainElement = doc.Root.FromPackage(ContentPackage);
bool allowOverriding = mainElement.IsOverride();
if (allowOverriding)
{
mainElement = mainElement.FirstElement();
}
var prefab = new SkillSettings(mainElement, this);
SkillSettings.Prefabs.Add(prefab, allowOverriding);
}
public override void UnloadFile()
{
SkillSettings.Prefabs.RemoveByFile(this);
}
public override void Sort()
{
SkillSettings.Prefabs.Sort();
}
}
}
@@ -0,0 +1,38 @@
using System;
using System.Collections.Immutable;
using System.Reflection;
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
#if CLIENT
sealed class SoundsFile : GenericPrefabFile<SoundPrefab>
{
public SoundsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override PrefabCollection<SoundPrefab> prefabs => SoundPrefab.Prefabs;
protected override SoundPrefab CreatePrefab(ContentXElement element)
{
var elemName = element.NameAsIdentifier();
if (SoundPrefab.TagToDerivedPrefab.ContainsKey(elemName))
{
return Activator.CreateInstance(SoundPrefab.TagToDerivedPrefab[elemName], new object[] { element, this }) as SoundPrefab;
}
return new SoundPrefab(element, this);
}
protected override bool MatchesPlural(Identifier identifier) => identifier == "sounds";
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
public override Md5Hash CalculateHash() => Md5Hash.Blank;
}
#else
sealed class SoundsFile : OtherFile
{
public SoundsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
#endif
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class StructureFile : GenericPrefabFile<StructurePrefab>
{
public StructureFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
protected override bool MatchesPlural(Identifier identifier) => identifier == "prefabs" || identifier == "structures";
protected override PrefabCollection<StructurePrefab> prefabs => StructurePrefab.Prefabs;
protected override StructurePrefab CreatePrefab(ContentXElement element)
{
return new StructurePrefab(element, this);
}
}
}
@@ -0,0 +1,38 @@
using System;
using System.Security.Cryptography;
namespace Barotrauma
{
public abstract class BaseSubFile : ContentFile
{
protected BaseSubFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path)
{
using var md5 = MD5.Create();
#warning TODO: this doesn't account for collisions, this should probably be using the PrefabCollection class like everything else
UintIdentifier = ToolBox.StringToUInt32Hash(Barotrauma.IO.Path.GetFileNameWithoutExtension(path.Value), md5);
}
public readonly UInt32 UintIdentifier;
public override void LoadFile()
{
SubmarineInfo.RefreshSavedSub(Path.Value);
}
public override void UnloadFile()
{
SubmarineInfo.RefreshSavedSub(Path.Value);
}
public override void Sort()
{
//Overrides for subs don't exist! Should we change this?
}
}
[NotSyncedInMultiplayer]
public class SubmarineFile : BaseSubFile
{
public SubmarineFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class TalentTreesFile : GenericPrefabFile<TalentTree>
{
public TalentTreesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "talenttree";
protected override bool MatchesPlural(Identifier identifier) => identifier == "talenttrees";
protected override PrefabCollection<TalentTree> prefabs => TalentTree.JobTalentTrees;
protected override TalentTree CreatePrefab(ContentXElement element)
{
return new TalentTree(element, this);
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class TalentsFile : GenericPrefabFile<TalentPrefab>
{
public TalentsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "talent";
protected override bool MatchesPlural(Identifier identifier) => identifier == "talents";
protected override PrefabCollection<TalentPrefab> prefabs => TalentPrefab.TalentPrefabs;
protected override TalentPrefab CreatePrefab(ContentXElement element)
{
return new TalentPrefab(element, this);
}
}
}
@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
public sealed class TextFile : ContentFile
{
public TextFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public override void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
var mainElement = doc.Root.FromPackage(ContentPackage);
var languageName = mainElement.GetAttributeIdentifier("language", TextManager.DefaultLanguage.Value);
LanguageIdentifier language = languageName.ToLanguageIdentifier();
if (!TextManager.TextPacks.ContainsKey(language))
{
TextManager.TextPacks.TryAdd(language, ImmutableHashSet<TextPack>.Empty);
}
var newPack = new TextPack(this, mainElement, language);
var newHashSet = TextManager.TextPacks[language].Add(newPack);
TextManager.TextPacks.TryRemove(language, out _);
TextManager.TextPacks.TryAdd(language, newHashSet);
TextManager.IncrementLanguageVersion();
}
public override void UnloadFile()
{
foreach (var kvp in TextManager.TextPacks.ToArray())
{
var newHashSet = kvp.Value.Where(p => p.ContentFile != this).ToImmutableHashSet();
TextManager.TextPacks.TryRemove(kvp.Key, out _);
if (newHashSet.Count != 0) { TextManager.TextPacks.TryAdd(kvp.Key, newHashSet); }
}
TextManager.IncrementLanguageVersion();
}
public override void Sort()
{
//Overrides for text packs don't exist! Should we change this?
}
}
}
@@ -0,0 +1,26 @@
using System.Xml.Linq;
#warning TODO: This file is just about the only thing that's actually somewhat okay about the current traitor system. Gut the whole thing.
#if CLIENT
using PrefabType = Barotrauma.TraitorMissionPrefab;
#elif SERVER
using PrefabType = Barotrauma.TraitorMissionPrefab.TraitorMissionEntry;
#endif
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class TraitorMissionsFile : GenericPrefabFile<PrefabType>
{
public TraitorMissionsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "TraitorMission";
protected override bool MatchesPlural(Identifier identifier) => identifier == "TraitorMissions";
protected override PrefabCollection<PrefabType> prefabs => PrefabType.Prefabs;
protected override PrefabType CreatePrefab(ContentXElement element)
{
return new PrefabType(element, this);
}
}
}
@@ -0,0 +1,100 @@
using System;
using Barotrauma.Extensions;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
namespace Barotrauma
{
#if CLIENT
public sealed class UIStyleFile : HashlessFile
{
public UIStyleFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
public void LoadFromXElement(ContentXElement parentElement, bool overriding)
{
Identifier elemName = parentElement.NameAsIdentifier();
Identifier elemNameWithFontSuffix = elemName.AppendIfMissing("Font");
if (parentElement.IsOverride())
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, true);
}
}
else if (GUIStyle.Fonts.ContainsKey(elemNameWithFontSuffix))
{
GUIFontPrefab prefab = new GUIFontPrefab(parentElement, this);
GUIStyle.Fonts[elemNameWithFontSuffix].Prefabs.Add(prefab, overriding);
}
else if (GUIStyle.Sprites.ContainsKey(elemName))
{
GUISpritePrefab prefab = new GUISpritePrefab(parentElement, this);
GUIStyle.Sprites[elemName].Prefabs.Add(prefab, overriding);
}
else if (GUIStyle.SpriteSheets.ContainsKey(elemName))
{
GUISpriteSheetPrefab prefab = new GUISpriteSheetPrefab(parentElement, this);
GUIStyle.SpriteSheets[elemName].Prefabs.Add(prefab, overriding);
}
else if (GUIStyle.Colors.ContainsKey(elemName))
{
GUIColorPrefab prefab = new GUIColorPrefab(parentElement, this);
GUIStyle.Colors[elemName].Prefabs.Add(prefab, overriding);
}
else if (elemName == "cursor")
{
GUICursorPrefab prefab = new GUICursorPrefab(parentElement, this);
GUIStyle.CursorSprite.Prefabs.Add(prefab, overriding);
}
else if (elemName == "style")
{
foreach (var element in parentElement.Elements())
{
LoadFromXElement(element, overriding);
}
}
else
{
GUIComponentStyle prefab = new GUIComponentStyle(parentElement, this);
GUIStyle.ComponentStyles.Add(prefab, overriding);
}
}
public override sealed void LoadFile()
{
XDocument doc = XMLExtensions.TryLoadXml(Path);
if (doc == null) { return; }
var rootElement = doc.Root.FromPackage(ContentPackage);
LoadFromXElement(rootElement, false);
}
public override sealed void UnloadFile()
{
GUIStyle.ComponentStyles.RemoveByFile(this);
GUIStyle.CursorSprite.Prefabs.RemoveByFile(this);
GUIStyle.Fonts.Values.ForEach(p => p.Prefabs.RemoveByFile(this));
GUIStyle.Sprites.Values.ForEach(p => p.Prefabs.RemoveByFile(this));
GUIStyle.SpriteSheets.Values.ForEach(p => p.Prefabs.RemoveByFile(this));
GUIStyle.Colors.Values.ForEach(p => p.Prefabs.RemoveByFile(this));
}
public override sealed void Sort()
{
GUIStyle.ComponentStyles.SortAll();
GUIStyle.CursorSprite.Prefabs.Sort();
GUIStyle.Fonts.Values.ForEach(p => p.Prefabs.Sort());
GUIStyle.Sprites.Values.ForEach(p => p.Prefabs.Sort());
GUIStyle.SpriteSheets.Values.ForEach(p => p.Prefabs.Sort());
GUIStyle.Colors.Values.ForEach(p => p.Prefabs.Sort());
}
}
#else
public sealed class UIStyleFile : OtherFile
{
public UIStyleFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
#endif
}
@@ -0,0 +1,31 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class UpgradeModulesFile : GenericPrefabFile<UpgradeContentPrefab>
{
public UpgradeModulesFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) =>
identifier == "upgrademodule" ||
identifier == "upgradecategory";
protected override bool MatchesPlural(Identifier identifier) =>
identifier == "upgrademodules";
protected override PrefabCollection<UpgradeContentPrefab> prefabs => UpgradeContentPrefab.PrefabsAndCategories;
protected override UpgradeContentPrefab CreatePrefab(ContentXElement element)
{
Identifier elemName = element.NameAsIdentifier();
if (elemName == "upgradecategory")
{
return new UpgradeCategory(element, this);
}
else
{
return new UpgradePrefab(element, this);
}
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma
{
[RequiredByCorePackage]
sealed class WreckAIConfigFile : GenericPrefabFile<WreckAIConfig>
{
public WreckAIConfigFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
protected override bool MatchesSingular(Identifier identifier) => identifier == "wreckaiconfig";
protected override bool MatchesPlural(Identifier identifier) => identifier == "wreckaiconfigs";
protected override PrefabCollection<WreckAIConfig> prefabs => WreckAIConfig.Prefabs;
protected override WreckAIConfig CreatePrefab(ContentXElement element)
{
return new WreckAIConfig(element, this);
}
}
}
@@ -0,0 +1,7 @@
namespace Barotrauma
{
public class WreckFile : BaseSubFile
{
public WreckFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
}
}