From c42705ffdffa77fc1df844c2d284fa162f734917 Mon Sep 17 00:00:00 2001 From: zznty <94796179+zznty@users.noreply.github.com> Date: Mon, 30 Dec 2024 05:47:30 +0700 Subject: [PATCH] Revert "rework plugin type patch" This reverts commit d4bf30a2 --- CringeLauncher/CringeLauncher.csproj | 2 +- CringeLauncher/Patches/PluginTypePatch.cs | 93 ++++++++--------------- 2 files changed, 34 insertions(+), 61 deletions(-) diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj index 2e39316..886fcaf 100644 --- a/CringeLauncher/CringeLauncher.csproj +++ b/CringeLauncher/CringeLauncher.csproj @@ -18,7 +18,7 @@ - + diff --git a/CringeLauncher/Patches/PluginTypePatch.cs b/CringeLauncher/Patches/PluginTypePatch.cs index f7aea71..dacf7a3 100644 --- a/CringeLauncher/Patches/PluginTypePatch.cs +++ b/CringeLauncher/Patches/PluginTypePatch.cs @@ -3,7 +3,7 @@ using HarmonyLib; using Sandbox.Game.World; using System.Reflection; using System.Reflection.Emit; -using VRage.Game; +using System.Runtime.Loader; using VRage.Game.ObjectBuilder; using VRage.Plugins; @@ -12,67 +12,40 @@ namespace CringeLauncher.Patches; [HarmonyPatch] internal static class PluginTypePatch { - [HarmonyPatch(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init))] - [HarmonyTranspiler] - private static IEnumerable MetadataTranspiler(IEnumerable instructions, ILGenerator generator) + [HarmonyTargetMethods] + public static IEnumerable TargetMethods() { - return new CodeMatcher(instructions, generator) - .SearchForward(b => b.opcode == OpCodes.Ldloc_2) - .Advance(-1) - .CreateLabel(out var regularPluginLabel) - .DeclareLocal(typeof(PluginWrapper), out var wrapper) - .DefineLabel(out var continueLabel) - .Insert(new(OpCodes.Ldloc_2), - new(OpCodes.Isinst, typeof(PluginWrapper)), new(OpCodes.Stloc, wrapper), - new(OpCodes.Ldloc_S, wrapper), - new(OpCodes.Brfalse_S, regularPluginLabel), - new(OpCodes.Ldloc_0), - new(OpCodes.Ldloc_S, wrapper), - new(OpCodes.Call, - AccessTools.PropertyGetter(typeof(PluginWrapper), nameof(PluginWrapper.InstanceType))), - new(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Type), nameof(Type.Assembly))), - CodeInstruction.Call(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.RegisterAssembly), - [typeof(Assembly)]), - new(OpCodes.Br_S, continueLabel)) - .SearchForward(b => b.opcode == OpCodes.Ldloca_S) - .AddLabels([continueLabel]) + yield return AccessTools.Method(typeof(MySession), "RegisterComponentsFromAssemblies"); + yield return AccessTools.Method(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init)); + } + + [HarmonyTranspiler] + public static IEnumerable Transpiler(IEnumerable 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(); } - [HarmonyPatch(typeof(MySession), "RegisterComponentsFromAssemblies")] - [HarmonyPrefix] - private static bool RegisterComponentsPrefix(MySession __instance) - { - __instance.m_componentsToLoad = [..__instance.GameDefinition.SessionComponents.Keys]; - __instance.m_componentsToLoad.ExceptWith(__instance.SessionComponentDisabled); - __instance.m_componentsToLoad.UnionWith(__instance.SessionComponentEnabled); - - __instance.RegisterComponentsFromAssembly(MyPlugins.SandboxAssembly); - __instance.RegisterComponentsFromAssembly(MyPlugins.SandboxGameAssembly); - __instance.RegisterComponentsFromAssembly(MyPlugins.GameAssembly); - - foreach (var (context, ids) in __instance.ScriptManager.ScriptsPerMod) - { - foreach (var id in ids) - { - __instance.RegisterComponentsFromAssembly(__instance.ScriptManager.Scripts[id], true, context); - } - } - - foreach (var plugin in MyPlugins.Plugins) - { - var type = plugin is PluginWrapper wrapper ? wrapper.InstanceType : plugin.GetType(); - - __instance.RegisterComponentsFromAssembly(type.Assembly, true); - } - - foreach (var component in __instance.m_sessionComponents.Values) - { - if (component.ModContext is null or { IsBaseGame: true }) - __instance.m_sessionComponentForDrawAsync.Add(component); - else - __instance.m_sessionComponentForDraw.Add(component); - } - return false; - } + //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(); }