diff --git a/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/ModConfig.xml b/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/ModConfig.xml index 363f7695b..cd06c211b 100644 --- a/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/ModConfig.xml +++ b/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/ModConfig.xml @@ -2,4 +2,7 @@ + + + diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs index 0c0fad9cd..4a3ec7268 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Xml.Linq; +using System.Xml.Serialization; using Barotrauma.LuaCs; using Barotrauma.Steam; using OneOf; @@ -44,6 +45,7 @@ public record AssemblyResourceInfo : BaseResourceInfo, IAssemblyResourceInfo public string FriendlyName { get; init; } public bool IsScript { get; init; } public bool UseInternalAccessName { get; init; } + public bool IsReferenceModeOnly { get; init; } } /// @@ -81,9 +83,12 @@ public record ConfigInfo : IConfigInfo public record ConfigProfileInfo : IConfigProfileInfo { + /// + /// Profile name. + /// public string InternalName { get; init; } public ContentPackage OwnerPackage { get; init; } - public IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; init; } + public IReadOnlyList<(string SettingName, XElement Element)> ProfileValues { get; init; } } #endregion diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IBaseInfoDefinitions.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IBaseInfoDefinitions.cs index 4f5cb032b..2326ecce2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IBaseInfoDefinitions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IBaseInfoDefinitions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.DataAnnotations; using System.Globalization; +using System.Xml.Serialization; namespace Barotrauma.LuaCs.Data; @@ -24,12 +25,14 @@ public interface IPlatformInfo /// Platforms that these localization files should be loaded for. /// [Required] + [XmlAttribute("Platform")] Platform SupportedPlatforms { get; } /// /// Targets that these localization files should be loaded for. /// [Required] + [XmlAttribute("Target")] Target SupportedTargets { get; } } @@ -44,6 +47,7 @@ public interface IResourceInfo : IPlatformInfo /// Specifies the loading order for all assets of the same type (ie. styles, assemblies, etc.) from /// the same . Lower number is higher priority, see /// + [XmlAttribute("LoadPriority")] int LoadPriority { get; } /// @@ -56,5 +60,6 @@ public interface IResourceInfo : IPlatformInfo /// Marks this resource as optional (ie. Cross-CP content). Setting this to true will allow the dependency system to /// try and order the loading but not fail if it runs into circular dependency issues. /// + [XmlAttribute("Optional")] bool Optional { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs index 5d5f9065d..28e9a6e1a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IConfigProfileInfo.cs @@ -5,5 +5,5 @@ namespace Barotrauma.LuaCs.Data; public interface IConfigProfileInfo : IDataInfo { - IReadOnlyList<(string ConfigName, XElement Element)> ProfileValues { get; } + IReadOnlyList<(string SettingName, XElement Element)> ProfileValues { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IDataInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IDataInfo.cs index d49be249b..652ddd967 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IDataInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IDataInfo.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Xml.Serialization; namespace Barotrauma.LuaCs.Data; @@ -11,6 +12,7 @@ public interface IDataInfo : IEqualityComparer, IEquatable /// /// Internal name unique within the resources inside a package. /// + [XmlAttribute("Name")] string InternalName { get; } /// /// The package this information belongs to. diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs index f40850cfa..32d17a16e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Runtime.CompilerServices; +using System.Xml.Serialization; namespace Barotrauma.LuaCs.Data; @@ -18,6 +19,7 @@ public interface ILuaScriptResourceInfo : IBaseResourceInfo /// /// Should this script be run automatically. /// + [XmlAttribute("IsAutorun")] public bool IsAutorun { get; } } @@ -27,17 +29,27 @@ public interface IAssemblyResourceInfo : IBaseResourceInfo /// The friendly name of the assembly. Script files belonging to the same assembly should all have the same name. /// Legacy scripts will all be given the sanitized name of the Content Package they belong to. /// + [XmlAttribute("FriendlyName")] public string FriendlyName { get; } /// /// Is this entry referring to a script file collection. /// + [XmlAttribute("IsScript")] public bool IsScript { get; } /// /// [Required(IsScript: true)] Whether the internal compiled assembly name should be named to enabled use of the /// attribute. /// + [XmlAttribute("UseInternalAccessName")] public bool UseInternalAccessName { get; } + + /// + /// Should the following resources only be used for Compilation MetadataReference. + /// NOTE: Affects the entire package's assembly resources, meant for internal use only. + /// + [XmlAttribute("IsReferenceModeOnly")] + public bool IsReferenceModeOnly { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs index 6a323c12e..bd82efe1f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs @@ -208,6 +208,10 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService AreOperationRunning = true; foreach (var data in _loadedAssemblyData.Values) { + if (data.AssemblyReference is null) + { + continue; + } yield return data.AssemblyReference; } AreOperationRunning = false; @@ -356,10 +360,10 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService if (additionalDependencyPaths.Any()) { var r = AddDependencyPaths(additionalDependencyPaths); - if (!r.IsFailed) + if (r.IsFailed) { // we have errors, loading may not work. - return FluentResults.Result.Fail(new Error($"Failed to load dependency paths.") + return FluentResults.Result.Fail(new Error($"Failed to load dependency paths for '{assemblyFilePath}' with paths: {additionalDependencyPaths.Aggregate((s, ac) => $"{ac}| P={s}")}.") .WithMetadata(MetadataType.ExceptionObject, this) .WithMetadata(MetadataType.RootObject, assemblyFilePath)) .WithErrors(r.Errors); @@ -379,7 +383,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService try { var assembly = LoadFromAssemblyPath(sanitizedFilePath); - _loadedAssemblyData[assembly] = new AssemblyData(assembly, sanitizedFilePath); + _loadedAssemblyData[assembly] = new AssemblyData(assembly, assembly.Location); return new Result().WithSuccess($"Loaded assembly '{assembly.GetName()}'").WithValue(assembly); } catch (FileNotFoundException fnfe) diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigFileParserService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigFileParserService.cs index 1a6f63933..33569f85b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigFileParserService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigFileParserService.cs @@ -79,7 +79,8 @@ public sealed class ModConfigFileParserService : // Type Specific FriendlyName = src.Element.GetAttributeString("FriendlyName", string.Empty), IsScript = src.Element.GetAttributeBool("IsScript", false), - UseInternalAccessName = src.Element.GetAttributeBool("UseInternalAccessName", false) + UseInternalAccessName = src.Element.GetAttributeBool("UseInternalAccessName", false), + IsReferenceModeOnly = src.Element.GetAttributeBool("IsReferenceModeOnly", false) }; } @@ -211,8 +212,8 @@ public sealed class ModConfigFileParserService : private (Platform Platform, Target Target) GetRuntimeEnvironment(XElement element) { return ( - Platform: element.GetAttributeEnum("Platform", Platform.Windows | Platform.Linux | Platform.OSX), - Target: element.GetAttributeEnum("Target", Target.Client | Target.Server)); + Platform: element.GetAttributeEnum("Platform", Platform.Any), + Target: element.GetAttributeEnum("Target", Target.Any)); } private async Task>> TryParseGenericResourcesAsync(IEnumerable sources) diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigService.cs index cd3ea8085..e4bc8897a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ModConfigService.cs @@ -264,7 +264,8 @@ public sealed class ModConfigService : IModConfigService FriendlyName = $"{src.Name}.{searchPathways.SubFolder.Replace('/','.')}", IncompatiblePackages = ImmutableArray.Empty, RequiredPackages = ImmutableArray.Empty, - IsScript = false + IsScript = false, + IsReferenceModeOnly = false }); } } @@ -304,7 +305,8 @@ public sealed class ModConfigService : IModConfigService IncompatiblePackages = ImmutableArray.Empty, RequiredPackages = ImmutableArray.Empty, UseInternalAccessName = true, - IsScript = true + IsScript = true, + IsReferenceModeOnly = false }); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs index c020949da..ecac7daaf 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs @@ -86,6 +86,29 @@ public class PluginManagementService : IAssemblyManagementService .ToString(), ScriptParseOptions); + private ImmutableArray _baseMetadataReferences = ImmutableArray.Empty; + private IEnumerable BaseMetadataReferences + { + get + { + if (_baseMetadataReferences.IsDefaultOrEmpty) + { + _baseMetadataReferences = Basic.Reference.Assemblies.Net80.References.All + .Union(AssemblyLoadContext.Default.Assemblies + .Where(ass => + !ass.IsDynamic && + !ass.GetName().FullName.EndsWith("Barotrauma.Core") && + !ass.GetName().FullName.EndsWith("Barotrauma") && + !ass.GetName().FullName.EndsWith("DedicatedServer")) + .Select(MetadataReference (ass) => MetadataReference.CreateFromFile(ass.Location))) + .Where(ar => ar is not null) + .ToImmutableArray(); + } + + return _baseMetadataReferences; + } + } + #endregion #region Disposal @@ -213,14 +236,35 @@ public class PluginManagementService : IAssemblyManagementService public Result> GetImplementingTypes(bool includeInterfaces = false, bool includeAbstractTypes = false, bool includeDefaultContext = true) { -#if !DEBUG - throw new NotImplementedException(); -#endif + if (includeInterfaces) + { + includeAbstractTypes = true; + } + + using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + var builder = ImmutableArray.CreateBuilder(); - foreach (var ass in AppDomain.CurrentDomain.GetAssemblies()) + if (includeDefaultContext) { - foreach (var type in ass.GetSafeTypes()) + foreach (var ass in AssemblyLoadContext.Default.Assemblies) + { + AddTypesFromAssembly(ass); + } + } + + foreach (var ass in _assemblyLoaders.Values.Where(al => !al.IsReferenceOnlyMode).SelectMany(al => al.Assemblies)) + { + AddTypesFromAssembly(ass); + } + + return builder.ToImmutable(); + + + void AddTypesFromAssembly(Assembly assembly) + { + foreach (var type in assembly.GetSafeTypes()) { if ((includeInterfaces || !type.IsInterface) && (includeAbstractTypes || !type.IsAbstract) @@ -230,8 +274,6 @@ public class PluginManagementService : IAssemblyManagementService } } } - - return builder.ToImmutable(); } public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false, @@ -255,9 +297,21 @@ public class PluginManagementService : IAssemblyManagementService return type; } + + foreach (var ass in AssemblyLoadContext.Default.Assemblies) + { + if (ass.GetType(typeName, false, false) is not {} type2 || (!includeInterfaces && type2.IsInterface)) + { + continue; + } + + return isByRefType ? type2.MakeByRefType() : type2; + } } - foreach (var ass in AssemblyLoadContext.All.SelectMany(alc => alc.Assemblies)) + foreach (var ass in AssemblyLoadContext.All + .Where(alc => alc != AssemblyLoadContext.Default) + .SelectMany(alc => alc.Assemblies)) { if (ass.GetType(typeName, false, false) is not {} type || (!includeInterfaces && type.IsInterface)) { @@ -426,7 +480,7 @@ public class PluginManagementService : IAssemblyManagementService new IAssemblyLoaderService.LoaderInitData( InstanceId: Guid.NewGuid(), contentPackRes.Key.Name, - IsReferenceMode: false, + IsReferenceMode: contentPackRes.Any(r => r.IsReferenceModeOnly), OwnerPackage: contentPackRes.Key, OnUnload: OnAssemblyLoaderUnloading, OnResolvingManaged: OnAssemblyLoaderResolvingManaged, @@ -465,7 +519,7 @@ public class PluginManagementService : IAssemblyManagementService new IAssemblyLoaderService.LoaderInitData( InstanceId: Guid.NewGuid(), contentPackRes.Key.Name, - IsReferenceMode: false, + IsReferenceMode: contentPackRes.Any(r => r.IsReferenceModeOnly), OwnerPackage: contentPackRes.Key, OnUnload: OnAssemblyLoaderUnloading, OnResolvingManaged: OnAssemblyLoaderResolvingManaged, @@ -550,35 +604,13 @@ public class PluginManagementService : IAssemblyManagementService IEnumerable GetMetadataReferences() { -#if !DEBUG - throw new NotImplementedException($"Needs to use publicized barotrauma assemblies and cache metadata."); -#endif - var publicizedDir = Path.Combine(Directory.GetCurrentDirectory(), "Publicized"); - - string[] publicizedAssemblies = + var builder = ImmutableArray.CreateBuilder(); + builder.AddRange(BaseMetadataReferences); + foreach (var loaderService in _assemblyLoaders) { -#if CLIENT - "Barotrauma", -#elif SERVER - "DedicatedServer", -#endif - "BarotraumaCore" - }; - - var publicizedRefs = publicizedAssemblies - .Select(name => Path.Combine(publicizedDir, $"{name}.dll")) - .Where(File.Exists) - .Select(path => MetadataReference.CreateFromFile(path)); - - var runtimeRefs = AppDomain.CurrentDomain.GetAssemblies() - .Where(ass => - !string.IsNullOrWhiteSpace(ass.Location) && - !publicizedAssemblies.Contains(ass.GetName().Name)) - .Select(ass => MetadataReference.CreateFromFile(ass.Location)); - - return Basic.Reference.Assemblies.Net80.References.All - .Union(runtimeRefs) - .Union(publicizedRefs); + builder.AddRange(loaderService.Value.AssemblyReferences.Where(ar => ar is not null)); + } + return builder.ToImmutable(); } }