fix: Fixes assembly loading. (#759)

* `AssemblyHandler.Assemblies` will now only contain assemblies listed in `assemblies.json`
* `assemblies.json` has been updated to only contain asssemblies directly loaded by the server. Namely, only `UOContent.dll`.
  * Specifically assemblies loaded by assemblies.json are subject to check for `Configure` and `Initialize` methods.
* `modernuo.json` now has a new property called `assemblyDirectories`. This will be automatically set to `Distribution/Assemblies` (absolute path on your machine).
  * You can add more directories to this list.
* All assemblies in assemblies.json _AND_ dependents of any assembly will be searched for in the directories specified by `assemblyDirectories`.
This commit is contained in:
Kamron Batman 2021-09-03 23:35:44 -07:00 committed by GitHub
parent 0d1fffd9fc
commit 54e56d2fc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 9 deletions

View file

@ -1,9 +1,3 @@
[ [
"Argon2.Bindings.dll",
"BouncyCastle.Crypto.dll",
"MailKit.dll",
"MimeKit.dll",
"Microsoft.Extensions.FileSystemGlobbing.dll",
"Zlib.Bindings.dll",
"UOContent.dll" "UOContent.dll"
] ]

View file

@ -29,13 +29,71 @@ namespace Server
private static TypeCache m_NullCache; private static TypeCache m_NullCache;
public static Assembly[] Assemblies { get; set; } public static Assembly[] Assemblies { get; set; }
public static void LoadScripts(string[] files) internal static Assembly AssemblyResolver(object sender, ResolveEventArgs args) =>
LoadAssemblyByAssemblyName(args.Name);
private static void EnsureAssemblyDirectories()
{
if (ServerConfiguration.AssemblyDirectories.Count == 0)
{
ServerConfiguration.AssemblyDirectories.Add(Path.Combine(Core.BaseDirectory, "Assemblies"));
ServerConfiguration.Save();
}
}
public static Assembly LoadAssemblyByAssemblyName(string fullAssemblyName)
{
var assemblyName = new AssemblyName(fullAssemblyName);
var assemblyFile = $"{assemblyName.Name}.dll";
EnsureAssemblyDirectories();
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
foreach (var assemblyDir in assemblyDirectories)
{
var assemblyPath = Path.Combine(assemblyDir, assemblyFile);
if (File.Exists(assemblyPath))
{
var assemblyNameCheck = AssemblyName.GetAssemblyName(assemblyPath);
if (assemblyNameCheck.FullName == assemblyName.FullName)
{
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
}
}
}
return null;
}
public static Assembly LoadAssemblyByFileName(string assemblyFile)
{
EnsureAssemblyDirectories();
var assemblyDirectories = ServerConfiguration.AssemblyDirectories;
foreach (var assemblyDir in assemblyDirectories)
{
var assemblyPath = Path.Combine(assemblyDir, assemblyFile);
if (File.Exists(assemblyPath))
{
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
}
}
return null;
}
public static void LoadAssemblies(string[] files)
{ {
var assemblies = new Assembly[files.Length]; var assemblies = new Assembly[files.Length];
for (var i = 0; i < files.Length; i++) for (var i = 0; i < files.Length; i++)
{ {
assemblies[i] = AssemblyLoadContext.Default.LoadFromAssemblyPath(files[i]); var assembly = LoadAssemblyByFileName(files[i]);
if (assembly == null)
{
throw new FileNotFoundException($"Could not load {files[i]}");
}
assemblies[i] = LoadAssemblyByFileName(files[i]);
} }
Assemblies = assemblies; Assemblies = assemblies;

View file

@ -32,6 +32,8 @@ namespace Server
private static ServerSettings m_Settings; private static ServerSettings m_Settings;
private static bool m_Mocked; private static bool m_Mocked;
public static List<string> AssemblyDirectories => m_Settings.AssemblyDirectories;
public static List<string> DataDirectories => m_Settings.DataDirectories; public static List<string> DataDirectories => m_Settings.DataDirectories;
public static List<IPEndPoint> Listeners => m_Settings.Listeners; public static List<IPEndPoint> Listeners => m_Settings.Listeners;

View file

@ -21,6 +21,9 @@ namespace Server
{ {
public class ServerSettings public class ServerSettings
{ {
[JsonPropertyName("assemblyDirectories")]
public List<string> AssemblyDirectories { get; set; } = new();
[JsonPropertyName("dataDirectories")] [JsonPropertyName("dataDirectories")]
public List<string> DataDirectories { get; set; } = new(); public List<string> DataDirectories { get; set; } = new();

View file

@ -365,6 +365,7 @@ namespace Server
{ {
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
AppDomain.CurrentDomain.AssemblyResolve += AssemblyHandler.AssemblyResolver;
LoopContext = new EventLoopContext(); LoopContext = new EventLoopContext();
@ -463,7 +464,7 @@ namespace Server
assemblyFiles[i] = Path.Join(BaseDirectory, "Assemblies", assemblyFiles[i]); assemblyFiles[i] = Path.Join(BaseDirectory, "Assemblies", assemblyFiles[i]);
} }
AssemblyHandler.LoadScripts(assemblyFiles); AssemblyHandler.LoadAssemblies(assemblyFiles);
VerifySerialization(); VerifySerialization();