diff --git a/Minecraft.Server.FourKit/PluginLoadContext.cs b/Minecraft.Server.FourKit/PluginLoadContext.cs index b7429e569..0f0b4c0c2 100644 --- a/Minecraft.Server.FourKit/PluginLoadContext.cs +++ b/Minecraft.Server.FourKit/PluginLoadContext.cs @@ -21,6 +21,13 @@ internal sealed class PluginLoadContext : AssemblyLoadContext if (assemblyName.Name == typeof(ServerPlugin).Assembly.GetName().Name) return typeof(ServerPlugin).Assembly; + foreach (var alc in AssemblyLoadContext.All) + { + var existing = alc.Assemblies + .FirstOrDefault(a => a.GetName().Name == assemblyName.Name); + if (existing != null) return existing; + } + string? path = _resolver.ResolveAssemblyToPath(assemblyName); if (path != null) return LoadFromAssemblyPath(path); diff --git a/Minecraft.Server.FourKit/PluginLoader.cs b/Minecraft.Server.FourKit/PluginLoader.cs index baecfcd0e..2e842cf9a 100644 --- a/Minecraft.Server.FourKit/PluginLoader.cs +++ b/Minecraft.Server.FourKit/PluginLoader.cs @@ -81,7 +81,13 @@ internal sealed class PluginLoader var assembly = context.LoadFromAssemblyPath(Path.GetFullPath(dllPath)); int found = 0; - foreach (var type in assembly.GetTypes()) + Type[] types; + try { + types = assembly.GetTypes(); + } catch (ReflectionTypeLoadException ex) { + types = ex.Types.Where(t => t != null).ToArray()!; + } + foreach (var type in types) { if (type.IsAbstract || type.IsInterface) continue; @@ -173,9 +179,10 @@ internal sealed class PluginLoader MethodInfo? method = type.GetMethod(camelName, DeclaredPublic, Type.EmptyTypes) ?? type.GetMethod(pascalName, DeclaredPublic, Type.EmptyTypes); - if (method != null) - { - method.Invoke(plugin, null); + try { + method?.Invoke(plugin, null); + } catch (TargetInvocationException ex) { + throw ex.InnerException ?? ex; } } diff --git a/Minecraft.Server.FourKit/docs/plugin-creation.md b/Minecraft.Server.FourKit/docs/plugin-creation.md index a1d4cf1e3..f5a7fc427 100644 --- a/Minecraft.Server.FourKit/docs/plugin-creation.md +++ b/Minecraft.Server.FourKit/docs/plugin-creation.md @@ -264,6 +264,79 @@ When a plugin folder is made, make sure the main dll matches the name of the fol You can also avoid this by using [Fody Costura](https://github.com/Fody/Costura) and bundle the dependencies into your DLL. +### Plugin Dependencies + +In certain cases, like if you wanted to implement an addon to an already existing plugin, you can put the plugin in your .csproj and use functions from that plugin! + +This is much like the Dependencies section above, but you shouldn't use Fody Costura for this. + +Example of implementing external plugin functions: + +```xml + + + .\CoolPlugin\CoolPlugin.dll + + +``` + +```csharp +public class PluginAddon : ServerPlugin +{ + public override void onEnable() { + CoolPlugin.CoolPluginAPI.CoolFunction(arg1, arg2, arg3); + } +} +``` + +```csharp +public class CoolPluginAPI +{ + // example API function + public static void CoolFunction(arg1, arg2, arg3) { + Console.WriteLine("This is a cool function!"); + } +} +``` + +If the API wants to access instance variables (like a list from the main ServerPlugin), you will have to make sure the instance is already initialized. + +This is because the plugin referencing the API might load before the actual plugin with the API. The API will be usable, but not the instance. + +You can do this by initializing the instance in the API if its not already initialized. + +```csharp +public class CoolPlugin : ServerPlugin +{ + private static CoolPlugin? _instance; + public static CoolPlugin? getInstance() => _instance; + internal static void setInstance(CoolPlugin inst) => _instance = inst; + + // example instance variable + internal List coolList = []; + + public override void onEnable() { + // initializes the instance if it isn't already initialized + instance ??= this; + } +} +``` + +```csharp +public class CoolPluginAPI +{ + // guarantee an instance when the API is used + internal static CoolPlugin? getCoolPlugin() { + if (CoolPlugin.getInstance() == null) CoolPlugin.setInstance(new CoolPlugin()); + return CoolPlugin.getInstance(); + } + + public static void CoolFunction(arg1, arg2, arg3) { + getCoolPlugin()?.coolList.Add(404); + } +} +``` + ### Fody Costura Fody Costura isnt very well documented, but heres the general usage guide that has worked for users: @@ -300,4 +373,4 @@ Fody Costura isnt very well documented, but heres the general usage guide that h Build

After you've done all this, it should build and put all dependencies into one DLL in your output folder.

- \ No newline at end of file +