Unstable 0.17.0.0
This commit is contained in:
+117
@@ -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<T> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user