Skip to content

Commit

Permalink
Merge pull request #13 from DanielMcAssey/dev/improve-plugin-loading
Browse files Browse the repository at this point in the history
fix(server): improve plugin loading
  • Loading branch information
DanielMcAssey authored Jan 24, 2025
2 parents 12642c8 + 5d1dd10 commit dc5dc9f
Showing 1 changed file with 47 additions and 15 deletions.
62 changes: 47 additions & 15 deletions GLOKON.Baiters.Core/Plugins/PluginLoader.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Serilog;
using System.Reflection;
using System.Runtime.Loader;

namespace GLOKON.Baiters.Core.Plugins
{
Expand All @@ -22,40 +23,42 @@ public static void LoadPlugins(GameManager gm)
{
try
{
AssemblyName thisFile = AssemblyName.GetAssemblyName(pluginPath); ;
pluginAssm.Add(Assembly.LoadFrom(pluginPath));
}
catch (Exception ex)
{
Log.Error(ex, "Failed to load plugin file ({PluginPath})", pluginPath);
Log.Error(ex, "Failed to load plugin file ({0})", pluginPath);
}
}

AssemblyLoadContext.Default.Resolving += Default_Resolving;
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

foreach (var assembly in pluginAssm)
{
Type[] pluginTypes = assembly.GetTypes()
.Where((type) => type.IsClass && type.IsSubclassOf(typeof(BaitersPlugin)))
.ToArray();

foreach (Type pluginType in pluginTypes)
try
{
if (Activator.CreateInstance(pluginType, gm) is BaitersPlugin plugin)
Type[] pluginTypes = assembly.GetTypes()
.Where((type) => type.IsClass && type.IsSubclassOf(typeof(BaitersPlugin)))
.ToArray();

foreach (Type pluginType in pluginTypes)
{
try
if (Activator.CreateInstance(pluginType, gm) is BaitersPlugin plugin)
{
plugin.OnInit();
Plugins.Add(plugin);
Log.Information("{0}:{1} plugin loaded by {2}", plugin.Name, plugin.Version, plugin.Author);
}
catch (Exception ex)
else
{
Log.Error(ex, "Failed to initialize plugin {0}:{1}", plugin.Name, plugin.Version);
Log.Error("Failed to instantiate plugin ({0})", pluginType.FullName);
}
}
else
{
Log.Error("Failed to create plugin ({0})", pluginType.FullName);
}
}
catch (Exception ex)
{
Log.Error(ex, "Failed to load plugin ({0})", assembly.FullName);
}
}
}
Expand All @@ -74,8 +77,37 @@ public static void UnloadPlugins()
}
}

AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
AssemblyLoadContext.Default.Resolving -= Default_Resolving;
Plugins.Clear();
GC.Collect();
}

private static Assembly? Default_Resolving(AssemblyLoadContext context, AssemblyName assembly)
{
Log.Verbose("Attempting to resolve {0}", assembly);

string assemblyPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"./plugins/{assembly.Name}.dll"));
return context.LoadFromAssemblyPath(assemblyPath);
}

private static Assembly? CurrentDomain_AssemblyResolve(object? sender, ResolveEventArgs args)
{
Assembly? assembly = null;

// Ignore version for internal dependencies
if (args.Name.Contains("GLOKON.Baiters.Core") || args.Name.Contains("GLOKON.Baiters.GodotInterop"))
{
var assemblyName = new AssemblyName(args.Name);

// Prevents infinte loop, as args will contain the assembly FullName once resolved
if (assemblyName.Name != args.Name)
{
assembly = ((AppDomain)sender).Load(assemblyName.Name);

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / build_and_release

Converting null literal or possible null value to non-nullable type.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / build_and_release

Dereference of a possibly null reference.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / build_and_release

Possible null reference argument for parameter 'assemblyString' in 'Assembly AppDomain.Load(string assemblyString)'.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (ubuntu-latest, linux-x64) / build-server

Converting null literal or possible null value to non-nullable type.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (ubuntu-latest, linux-x64) / build-server

Dereference of a possibly null reference.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (ubuntu-latest, linux-x64) / build-server

Possible null reference argument for parameter 'assemblyString' in 'Assembly AppDomain.Load(string assemblyString)'.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (windows-latest, win-x64) / build-server

Converting null literal or possible null value to non-nullable type.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (windows-latest, win-x64) / build-server

Dereference of a possibly null reference.

Check warning on line 106 in GLOKON.Baiters.Core/Plugins/PluginLoader.cs

View workflow job for this annotation

GitHub Actions / Build Server (windows-latest, win-x64) / build-server

Possible null reference argument for parameter 'assemblyString' in 'Assembly AppDomain.Load(string assemblyString)'.
}
}

return assembly;
}
}
}

0 comments on commit dc5dc9f

Please sign in to comment.