Fix registering components from plugin assemblies
All checks were successful
Build / Compute Version (push) Successful in 5s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 1m33s
Build / Build Nuget package (NuGet) (push) Successful in 3m26s
Build / Build Nuget package (CringePlugins) (push) Successful in 3m50s
Build / Build Nuget package (SharedCringe) (push) Successful in 2m50s
Build / Build Launcher (push) Successful in 3m34s

This commit is contained in:
2024-12-10 23:39:21 -05:00
parent 530e05875f
commit 5af1c51be8
2 changed files with 53 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
using CringePlugins.Loader;
using HarmonyLib;
using Sandbox.Game.World;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Loader;
using VRage.Game.ObjectBuilder;
using VRage.Plugins;
namespace CringeLauncher.Patches;
[HarmonyPatch]
internal static class PluginTypePatch
{
[HarmonyTargetMethods]
public static IEnumerable<MethodInfo> TargetMethods()
{
yield return AccessTools.Method(typeof(MySession), "RegisterComponentsFromAssemblies");
yield return AccessTools.Method(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init));
}
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
//replaces plugin.GetType() with GetPluginType(plugin)
var pve = AccessTools.Method(typeof(Assembly), nameof(Assembly.Load), [typeof(AssemblyName)]);
var method = AccessTools.Method(typeof(object), nameof(GetType));
var getter = AccessTools.PropertyGetter(typeof(MyPlugins), nameof(MyPlugins.Plugins));
var matcher = new CodeMatcher(instructions);
if (original.DeclaringType == typeof(MySession))
{
matcher = matcher
.SearchForward(b => b.Calls(pve))
.Set(OpCodes.Call, AccessTools.Method(typeof(PluginTypePatch), nameof(LoadAssembly)));
}
return matcher
.SearchForward(b => b.Calls(getter))
.SearchForward(b => b.Calls(method))
.Set(OpCodes.Call, AccessTools.Method(typeof(PluginTypePatch), nameof(GetPluginType)))
.InstructionEnumeration();
}
//Assembly.Load is called in MySession.RegisterComponentsFromAssemblies. When patching, it uses the wrong context
//todo: maybe there's a better way to do this?
private static Assembly LoadAssembly(AssemblyName name) => AssemblyLoadContext.GetLoadContext(typeof(Launcher).Assembly)!.LoadFromAssemblyName(name);
private static Type GetPluginType(IPlugin plugin) => plugin is PluginWrapper wrapper ? wrapper.InstanceType : plugin.GetType();
}