diff --git a/Barotrauma/BarotraumaShared/Luatrauma.props b/Barotrauma/BarotraumaShared/Luatrauma.props index ebc46700a..a17acc078 100644 --- a/Barotrauma/BarotraumaShared/Luatrauma.props +++ b/Barotrauma/BarotraumaShared/Luatrauma.props @@ -7,7 +7,7 @@ - + diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs index 274d41c0c..514188b3f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/DataInterfaceImplementations.cs @@ -43,6 +43,7 @@ public record AssemblyResourceInfo : BaseResourceInfo, IAssemblyResourceInfo { public string FriendlyName { get; init; } public bool IsScript { get; init; } + public bool UseInternalAccessName { get; init; } } /// diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs index 366578fdb..f40850cfa 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Data/IResourceInfoDeclarations.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; +using System.Runtime.CompilerServices; namespace Barotrauma.LuaCs.Data; @@ -31,6 +32,12 @@ public interface IAssemblyResourceInfo : IBaseResourceInfo /// Is this entry referring to a script file collection. /// public bool IsScript { get; } + + /// + /// [Required(IsScript: true)] Whether the internal compiled assembly name should be named to enabled use of the + /// attribute. + /// + public bool UseInternalAccessName { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs index 223e83ba0..1d32ce229 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs @@ -22,6 +22,7 @@ using FluentResults; using ImpromptuInterface; using LightInject; using Microsoft.Toolkit.Diagnostics; +using AssemblyLoader = Barotrauma.LuaCs.Services.AssemblyLoader; namespace Barotrauma { @@ -185,6 +186,7 @@ namespace Barotrauma servicesProvider.RegisterServiceResolver(factory => factory.GetInstance() as ILuaCsHook); servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); + servicesProvider.RegisterServiceType(ServiceLifetime.Transient); servicesProvider.RegisterServiceResolver(factory => factory.GetInstance()); servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Transient); diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LoggerService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LoggerService.cs index fc5e23586..f0bfc110a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LoggerService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/LoggerService.cs @@ -182,7 +182,7 @@ public partial class LoggerService : ILoggerService return; } - if (result.Errors.Any()) + if (result.IsFailed) { foreach (var error in result.Errors) { @@ -192,7 +192,7 @@ public partial class LoggerService : ILoggerService } else { - LogError(error.Message); + LogError($"FluentResults::IError: {error.Message}"); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PackageManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PackageManagementService.cs index 65ad767df..c26a38e83 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PackageManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PackageManagementService.cs @@ -261,7 +261,9 @@ public sealed class PackageManagementService : IPackageManagementService return result; } - private static ImmutableArray SelectCompatible(ImmutableArray resources, ImmutableHashSet enabledPackagesIdents, ImmutableArray loadingOrder) + private static ImmutableArray SelectCompatible(ImmutableArray resources, + ImmutableHashSet enabledPackagesIdents, + ImmutableArray loadingOrder) where T : IBaseResourceInfo { return resources @@ -289,14 +291,22 @@ public sealed class PackageManagementService : IPackageManagementService var result = new FluentResults.Result(); - result.WithReasons(UnloadPackages(toRemove).Reasons); + if (!toRemove.IsDefaultOrEmpty) + { + result.WithReasons(UnloadPackages(toRemove).Reasons); + } if (result.IsFailed) { return result; } - return result.WithReasons(LoadPackagesInfo(toAdd).Reasons); + if (!toAdd.IsDefaultOrEmpty) + { + result.WithReasons(LoadPackagesInfo(toAdd).Reasons); + } + + return result; } public FluentResults.Result StopRunningPackages() diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PluginManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PluginManagementService.cs index 6bc10f0d6..63b9e3a51 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PluginManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/PluginManagementService.cs @@ -7,114 +7,124 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Loader; +using System.Text; using System.Threading; using Barotrauma.Extensions; +using Barotrauma.IO; using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Events; using FluentResults; using FluentResults.LuaCs; using ImpromptuInterface.Build; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.Logging; using Microsoft.Toolkit.Diagnostics; using OneOf; namespace Barotrauma.LuaCs.Services; -public class PluginManagementService : IPluginManagementService, IAssemblyManagementService +public class PluginManagementService : IAssemblyManagementService { - private readonly Func _assemblyLoaderServiceFactory; - private readonly ConcurrentDictionary ResourceInfos, IAssemblyLoaderService Loader)> _packageAssemblyResources = new(); - private readonly ConcurrentDictionary> _pluginInstances = new(); - private readonly Lazy _eventService; - private readonly ConditionalWeakTable _unloadingAssemblyLoaders = new(); - private readonly ConditionalWeakTable> _assemblyTypesCache = new(); + #region CSHARP_COMPILATION_OPTIONS - public PluginManagementService( - Func assemblyLoaderServiceFactory, - Lazy eventService) - { - _assemblyLoaderServiceFactory = assemblyLoaderServiceFactory; - _eventService = eventService; - AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoadedGlobal; - } - - private void OnAssemblyLoadedGlobal(object sender, AssemblyLoadEventArgs args) - { - // cache types by name - try + private static readonly CSharpParseOptions ScriptParseOptions = CSharpParseOptions.Default + .WithPreprocessorSymbols(new[] { - var context = AssemblyLoadContext.GetLoadContext(args.LoadedAssembly); - if (context is not IAssemblyLoaderService loaderService) - return; - _eventService.Value.PublishEvent(sub => sub.OnAssemblyLoaded(args.LoadedAssembly)); - var lookupDict = new ConcurrentDictionary(); - foreach (var type in args.LoadedAssembly.GetSafeTypes()) - { - lookupDict[type.FullName ?? type.Name] = type; - } - _assemblyTypesCache.AddOrUpdate(args.LoadedAssembly, lookupDict); - } - catch (Exception e) - { - // ignored - return; - } - } +#if SERVER + "SERVER" +#elif CLIENT + "CLIENT" +#else + "UNDEFINED" +#endif +#if DEBUG + ,"DEBUG" +#endif + }); - private int _isDisposed = 0; - public bool IsDisposed - { - get => ModUtils.Threading.GetBool(ref _isDisposed); - private set => ModUtils.Threading.SetBool(ref _isDisposed, value); - } +#if WINDOWS + private const string PLATFORM_TARGET = "Windows"; +#elif OSX + private const string PLATFORM_TARGET = "OSX"; +#elif LINUX + private const string PLATFORM_TARGET = "Linux"; +#endif + +#if CLIENT + private const string ARCHITECTURE_TARGET = "Client"; +#elif SERVER + private const string ARCHITECTURE_TARGET = "Server"; +#endif + + private static readonly CSharpCompilationOptions CompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + .WithMetadataImportOptions(MetadataImportOptions.All) +#if DEBUG + .WithOptimizationLevel(OptimizationLevel.Debug) +#else + .WithOptimizationLevel(OptimizationLevel.Release) +#endif + .WithAllowUnsafe(true); + + private static readonly SyntaxTree BaseAssemblyImports = CSharpSyntaxTree.ParseText( + new StringBuilder() + .AppendLine("using System.Reflection;") + .AppendLine("using Barotrauma;") + .AppendLine("using System.Runtime.CompilerServices;") + .AppendLine("[assembly: IgnoresAccessChecksTo(\"BarotraumaCore\")]") +#if CLIENT + .AppendLine("[assembly: IgnoresAccessChecksTo(\"Barotrauma\")]") +#elif SERVER + .AppendLine("[assembly: IgnoresAccessChecksTo(\"DedicatedServer\")]") +#endif + .ToString(), + ScriptParseOptions); + + #endregion + + #region Disposal public void Dispose() { throw new NotImplementedException(); } + public bool IsDisposed { get; } public FluentResults.Result Reset() { - if (IsDisposed) - return FluentResults.Result.Fail($"{nameof(PluginManagementService)} is disposed!"); - - return FluentResults.Result.Fail("not implemented"); + throw new NotImplementedException(); } - public Result> GetImplementingTypes(bool includeInterfaces = false, - bool includeAbstractTypes = false, bool includeDefaultContext = true) + #endregion + + private IServicesProvider _serviceProvider; + private IAssemblyLoaderService.IFactory _assemblyLoaderFactory; + private IStorageService _storageService; + private ILoggerService _logger; + private readonly ConcurrentDictionary _assemblyLoaders = new(); + private readonly AsyncReaderWriterLock _operationsLock = new(); + + public PluginManagementService( + IServicesProvider serviceProvider, + IAssemblyLoaderService.IFactory assemblyLoaderFactory, + IStorageService storageService, + ILoggerService logger) { - var builder = ImmutableArray.CreateBuilder(); - - if (this._packageAssemblyResources.Any()) - { - foreach (var resource in this._packageAssemblyResources - .Where(res => !res.Value.Loader.IsReferenceOnlyMode)) - { - builder.AddRange(resource.Value.Loader.Assemblies - .SelectMany(assembly => assembly.GetSafeTypes()) - .Where(type => type.IsAssignableTo(typeof(T))) - .Where(type => includeInterfaces || !type.IsInterface) - .Where(type => includeAbstractTypes || !type.IsAbstract)); - } - } - - if (includeDefaultContext) - { - builder.AddRange(AssemblyLoadContext.Default.Assemblies - .SelectMany(assembly => assembly.GetSafeTypes()) - .Where(type => type.IsAssignableTo(typeof(T))) - .Where(type => includeInterfaces || !type.IsInterface) - .Where(type => includeAbstractTypes || !type.IsAbstract)); - } - - return builder.Count == 0 - ? FluentResults.Result.Fail($"Failed to find any types that implement {typeof(T).Name})") - : FluentResults.Result.Ok(builder.ToImmutable()); + Guard.IsNotNull(serviceProvider, nameof(serviceProvider)); + _serviceProvider = serviceProvider; + _assemblyLoaderFactory = assemblyLoaderFactory; + _storageService = storageService; + _logger = logger; } - public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = true, + public Result> GetImplementingTypes(bool includeInterfaces = false, bool includeAbstractTypes = false, + bool includeDefaultContext = true) + { + throw new NotImplementedException(); + } + + public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false, bool includeDefaultContext = true) { if (includeDefaultContext) @@ -144,91 +154,197 @@ public class PluginManagementService : IPluginManagementService, IAssemblyManage return null; } - public FluentResults.Result LoadAssemblyResources(ImmutableArray resources) - { - IService.CheckDisposed(this); - if (resources.IsDefaultOrEmpty) - { - ThrowHelper.ThrowArgumentNullException($"{nameof(LoadAssemblyResources)}: The resources list is empty!"); - } - - return FluentResults.Result.Fail("not implemented"); - } - public ImmutableArray> ActivateTypeInstances(ImmutableArray types, bool serviceInjection = true, bool hostInstanceReference = false) where T : IDisposable { + throw new NotImplementedException(); + } + + public FluentResults.Result LoadAssemblyResources(ImmutableArray resources) + { + if (resources.IsDefaultOrEmpty) + { + ThrowHelper.ThrowArgumentNullException($"{nameof(LoadAssemblyResources)} The resource list is empty.)"); + } + using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + var orderedContentPacks = resources.GroupBy(res => res.OwnerPackage) + .OrderBy(res => resources.FindIndex(r2 => r2.OwnerPackage == res.Key)) + .ToImmutableArray(); + + var result = new FluentResults.Result(); + + return FluentResults.Result.Fail($"{nameof(LoadAssemblyResources)}: Not Implemented!"); + throw new NotImplementedException(); + + foreach (var contentPack in orderedContentPacks) + { + LoadBinaries(contentPack); + LoadAndCompileScriptAssemblies(contentPack); + } + + return result; + + // helper methods + void LoadBinaries(IGrouping contentPackRes) + { + var binaries = contentPackRes.Where(cRes => !cRes.IsScript) + .OrderBy(bin => bin.LoadPriority) + .SelectMany(bin => bin.FilePaths) + .ToImmutableArray(); + + if (binaries.IsDefaultOrEmpty) + { + return; + } + + var assemblyLoader = _assemblyLoaders.GetOrAdd(contentPackRes.Key, (cp) => _assemblyLoaderFactory.CreateInstance( + new IAssemblyLoaderService.LoaderInitData( + InstanceId: Guid.NewGuid(), + contentPackRes.Key.Name, + IsReferenceMode: false, + OwnerPackage: contentPackRes.Key, + OnUnload: OnAssemblyLoaderUnloading, + OnResolvingManaged: OnAssemblyLoaderResolvingManaged, + OnResolvingUnmanagedDll: OnAssemblyLoaderResolvingUnmanaged + ))); + + var dependencyPaths = binaries + .Select(bin => System.IO.Path.GetDirectoryName(bin.FullPath)) + .Distinct() + .ToImmutableArray(); + + foreach (var binResource in binaries) + { + var res = assemblyLoader.LoadAssemblyFromFile(binResource.FullPath, dependencyPaths); + result.WithReasons(res.Reasons); #if DEBUG - return ImmutableArray>.Empty; + _logger.LogResults(res.ToResult()); #endif + if (res.IsFailed) + { + _logger.LogResults(res.ToResult()); + } + } + } + + void LoadAndCompileScriptAssemblies(IGrouping contentPackRes) + { + var scripts = contentPackRes.Where(cRes => cRes.IsScript) + .OrderBy(scr => scr.LoadPriority) + .Select(scr => (scr.FriendlyName, scr.FilePaths, scr.UseInternalAccessName)) + .GroupBy(scr => scr.FriendlyName) + .ToImmutableArray(); + + if (scripts.IsDefaultOrEmpty) + { + return; + } + + var metadataReferences = GetMetadataReferences(); + + var assemblyLoader = _assemblyLoaders.GetOrAdd(contentPackRes.Key, (cp) => _assemblyLoaderFactory.CreateInstance( + new IAssemblyLoaderService.LoaderInitData( + InstanceId: Guid.NewGuid(), + contentPackRes.Key.Name, + IsReferenceMode: false, + OwnerPackage: contentPackRes.Key, + OnUnload: OnAssemblyLoaderUnloading, + OnResolvingManaged: OnAssemblyLoaderResolvingManaged, + OnResolvingUnmanagedDll: OnAssemblyLoaderResolvingUnmanaged + ))); + + // create syntax trees + var syntaxTreesBuilder = ImmutableArray.CreateBuilder(); + + foreach (var resourceInfo in contentPackRes) + { + if (resourceInfo.FilePaths.IsDefaultOrEmpty) + { + ThrowHelper.ThrowArgumentNullException($"{nameof(LoadAndCompileScriptAssemblies)} The resource list is empty for package {resourceInfo.OwnerPackage}."); + } + + var loadRes = GetSourceFilesText(resourceInfo.FilePaths); + if (loadRes.IsFailed) + { + _logger.LogResults(loadRes.ToResult()); + continue; + } + + CancellationToken token = CancellationToken.None; + + syntaxTreesBuilder.Add(SyntaxFactory.ParseSyntaxTree( + text: loadRes.Value, + options: ScriptParseOptions, + path: null, + encoding: Encoding.Default, + cancellationToken: token + )); + } + + throw new NotImplementedException(); + } + + Result GetSourceFilesText(ImmutableArray resourceInfoFilePaths) + { + if (_storageService.LoadPackageTextFiles(resourceInfoFilePaths) is not { IsDefaultOrEmpty: false } res) + { + _logger.LogError($"{nameof(GetSourceFilesText)}: Failed to load source files for ContentPackage {resourceInfoFilePaths.First().ContentPackage?.Name}."); + return FluentResults.Result.Fail($"{nameof(GetSourceFilesText)}: Failed to load source files for ContentPackage {resourceInfoFilePaths.First().ContentPackage?.Name}."); + } + + var loadRes = new FluentResults.Result(); + StringBuilder sb = new StringBuilder(); + + foreach ((ContentPath Path, Result FileResult) loadResult in res) + { + if (loadResult.FileResult.IsFailed) + { + loadRes.WithErrors(loadResult.FileResult.Errors); + continue; + } + + sb.AppendLine(loadResult.FileResult.Value); + } + + if (loadRes.IsFailed) + { + return loadRes; + } + + return sb.ToString(); + } + + IEnumerable GetMetadataReferences() + { + return Basic.Reference.Assemblies.Net80.References.All; + } + } + + private IntPtr OnAssemblyLoaderResolvingUnmanaged(Assembly arg1, string arg2) + { + throw new NotImplementedException(); + } + + private Assembly OnAssemblyLoaderResolvingManaged(IAssemblyLoaderService arg1, AssemblyName arg2) + { + throw new NotImplementedException(); + } + + private void OnAssemblyLoaderUnloading(IAssemblyLoaderService loader) + { throw new NotImplementedException(); } public FluentResults.Result UnloadManagedAssemblies() { - var res = new FluentResults.Result(); - - // cleanup managed plugins - if (_pluginInstances.Any()) - { - foreach (var packageInstances in _pluginInstances) - { - if (!packageInstances.Value.Any()) - continue; - - foreach (var disposable in packageInstances.Value) - { - try - { - disposable.Dispose(); - } - catch (Exception e) - { - res = res.WithError(new ExceptionalError(e) - .WithMetadata(MetadataType.ExceptionObject, this)); - } - } - } - _pluginInstances.Clear(); - } - - _assemblyTypesCache.Clear(); - - // cleanup running assembly contexts - if (_packageAssemblyResources.Any()) - { - foreach (var resource in _packageAssemblyResources.ToImmutableDictionary()) - { - if (resource.Value.Loader is not null) - { - try - { - resource.Value.Loader.Dispose(); - _unloadingAssemblyLoaders.AddOrUpdate(resource.Value.Loader, resource.Key); - _packageAssemblyResources.TryRemove(resource); - _packageAssemblyResources.TryAdd(resource.Key, (resource.Value.ResourceInfos, null)); - } - catch (Exception e) - { - res = res.WithError(new ExceptionalError(e) - .WithMetadata(MetadataType.ExceptionObject, this)); - } - } - } - } - - return res.WithSuccess($"Unloading of managed assemblies started successfully,"); + return FluentResults.Result.Fail($"{nameof(UnloadManagedAssemblies)}: Not Implemented."); + throw new NotImplementedException(); } public Result GetLoadedAssembly(OneOf assemblyName, in Guid[] excludedContexts) { throw new NotImplementedException(); } - - public ImmutableArray GetDefaultMetadataReferences(bool includeDefaultContext = true) - { - throw new NotImplementedException(); - } - - public ImmutableArray AssemblyLoaderServices { get; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs index 3f9b5ef25..b35212eae 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/Processing/ModConfigFileParserService.cs @@ -79,6 +79,7 @@ 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) }; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ServicesProvider.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ServicesProvider.cs index 37e454431..d0a81f425 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ServicesProvider.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ServicesProvider.cs @@ -21,6 +21,8 @@ public class ServicesProvider : IServicesProvider { EnablePropertyInjection = false }); + + _serviceContainerInst.Register((f) => this); } public void RegisterServiceType(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IAssemblyManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IAssemblyManagementService.cs index 2499d55f8..d82105455 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IAssemblyManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IAssemblyManagementService.cs @@ -12,7 +12,7 @@ using OneOf; namespace Barotrauma.LuaCs.Services; -public interface IAssemblyManagementService : IReusableService +public interface IAssemblyManagementService : IPluginManagementService { /// @@ -22,17 +22,4 @@ public interface IAssemblyManagementService : IReusableService /// Guids of excluded contexts. /// On Success: The assembly.
On Failure: nothing.
FluentResults.Result GetLoadedAssembly(OneOf assemblyName, in Guid[] excludedContexts); - - /// - /// Gets all for all service-managed assemblies. - /// - /// collection for all service-managed, and default if selected, assemblies, if any are found. Returns an empty collection otherwise. - ImmutableArray GetDefaultMetadataReferences(bool includeDefaultContext = true); - - /// - /// Returns all active, managed assembly loaders. - /// - ImmutableArray AssemblyLoaderServices { get; } - - } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IPluginManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IPluginManagementService.cs index 700418bfb..83cd59981 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IPluginManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IPluginManagementService.cs @@ -32,13 +32,6 @@ public interface IPluginManagementService : IReusableService /// Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false, bool includeDefaultContext = true); - /// - /// Loads the provided assembly resources in the order of their dependencies and intra-mod priority load order. - /// - /// - /// Success/Failure and list of failed resources, if any. - FluentResults.Result LoadAssemblyResources(ImmutableArray resources); - /// /// Creates instances of the given type and provides Property Injection and instance reference caching. Disposes of /// all references that throw errors on @@ -50,6 +43,12 @@ public interface IPluginManagementService : IReusableService ImmutableArray> ActivateTypeInstances(ImmutableArray types, bool serviceInjection = true, bool hostInstanceReference = false) where T : IDisposable; + /// + /// Loads the provided assembly resources in the order of their dependencies and intra-mod priority load order. + /// + /// + /// Success/Failure and list of failed resources, if any. + FluentResults.Result LoadAssemblyResources(ImmutableArray resources); /// /// Unloads all managed , , and s. diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs index a7cebbd5c..7a82c8494 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/AssemblyLoader.cs @@ -24,6 +24,20 @@ using Path = System.IO.Path; namespace Barotrauma.LuaCs.Services; public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService { + public class Factory : IAssemblyLoaderService.IFactory + { + public IAssemblyLoaderService CreateInstance(IAssemblyLoaderService.LoaderInitData initData) + { + return new AssemblyLoader(initData); + } + + public void Dispose() + { + //stateless service + } + public bool IsDisposed => false; + } + public Guid Id { get; init; } public ContentPackage OwnerPackage { get; private set; } public bool IsReferenceOnlyMode { get; init; } @@ -55,7 +69,6 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService private int _operationsRunning; //internal - private readonly IAssemblyManagementService _assemblyManagementService; private readonly Action _onUnload; private readonly Func _onResolvingManaged; private readonly Func _onResolvingUnmanagedDll; @@ -68,7 +81,6 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService public AssemblyLoader(IAssemblyLoaderService.LoaderInitData initData) : base(isCollectible: true, name: initData.Name) { - _assemblyManagementService = initData.AssemblyManagementService; Id = initData.InstanceId; IsReferenceOnlyMode = initData.IsReferenceMode; this._onUnload = initData.OnUnload; @@ -217,7 +229,10 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService try { var p = Path.GetFullPath(path.CleanUpPath()); - _dependencyResolvers[p] = new AssemblyDependencyResolver(p); + if (!_dependencyResolvers.ContainsKey(p)) + { + _dependencyResolvers[p] = new AssemblyDependencyResolver(p); + } } catch (Exception ex) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/IAssemblyLoaderService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/IAssemblyLoaderService.cs index 071effa1a..c3dd6983a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/IAssemblyLoaderService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Plugins/IAssemblyLoaderService.cs @@ -13,6 +13,11 @@ namespace Barotrauma.LuaCs; public interface IAssemblyLoaderService : IService { + public interface IFactory : IService + { + IAssemblyLoaderService CreateInstance(LoaderInitData initData); + } + /// /// Constructor record for instancing. /// @@ -26,7 +31,6 @@ public interface IAssemblyLoaderService : IService /// /// public record LoaderInitData( - [Required][NotNull] IAssemblyManagementService AssemblyManagementService, [Required] Guid InstanceId, [Required][NotNull] string Name, [Required] bool IsReferenceMode,