Files
se-launcher/CringePlugins/Loader/PluginAssemblyLoadContext.cs
pas2704 02584dfcfb
All checks were successful
Build / Compute Version (push) Successful in 4s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 1m50s
Build / Build Nuget package (NuGet) (push) Successful in 1m50s
Build / Build Nuget package (CringePlugins) (push) Successful in 2m17s
Build / Build Nuget package (SharedCringe) (push) Successful in 2m38s
Build / Build Launcher (push) Successful in 3m16s
Allow plugins to find non-harmony types in other plugins
2024-11-03 18:34:34 -05:00

77 lines
2.3 KiB
C#

using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.Loader;
using CringeBootstrap.Abstractions;
using CringePlugins.Utils;
using SharedCringe.Loader;
namespace CringePlugins.Loader;
internal class PluginAssemblyLoadContext : DerivedAssemblyLoadContext
{
//todo: refactor?
public static readonly ConcurrentDictionary<string, Assembly> TypeToAssembly = [];
private readonly string _entrypointPath;
private readonly AssemblyDependencyResolver _dependencyResolver;
private readonly HashSet<string> _loadedTypes = [];
private Assembly? _assembly;
internal PluginAssemblyLoadContext(ICoreLoadContext parentContext, string entrypointPath) : base(parentContext, $"Plugin Context {Path.GetFileNameWithoutExtension(entrypointPath)}")
{
_entrypointPath = entrypointPath;
_dependencyResolver = new(entrypointPath);
Unloading += OnUnload;
}
public Assembly LoadEntrypoint()
{
if (_assembly is not null)
return _assembly;
_assembly = LoadFromAssemblyPath(_entrypointPath);
var module = _assembly.GetMainModule();
foreach (var type in module.GetTypes())
{
var name = type.FullName?.Replace('/', '+');
if (string.IsNullOrEmpty(name) || !_loadedTypes.Add(name))
continue;
TypeToAssembly[name] = _assembly;
}
return _assembly;
}
protected override Assembly? Load(AssemblyName assemblyName)
{
if (_dependencyResolver.ResolveAssemblyToPath(assemblyName) is { } path)
return LoadFromAssemblyPath(path);
return base.Load(assemblyName);
}
protected override nint LoadUnmanagedDll(string unmanagedDllName)
{
if (_dependencyResolver.ResolveUnmanagedDllToPath(unmanagedDllName) is { } path)
return LoadUnmanagedDllFromPath(path);
return base.LoadUnmanagedDll(unmanagedDllName);
}
private static void OnUnload(AssemblyLoadContext context)
{
if (context is not PluginAssemblyLoadContext pluginContext)
return;
foreach (var typeStr in pluginContext._loadedTypes)
{
TypeToAssembly.Remove(typeStr);
}
pluginContext._loadedTypes.Clear();
}
}