diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj
index 886fcaf..2e39316 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 dacf7a3..85fd092 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 System.Runtime.Loader;
+using VRage.Game;
using VRage.Game.ObjectBuilder;
using VRage.Plugins;
@@ -12,40 +12,67 @@ namespace CringeLauncher.Patches;
[HarmonyPatch]
internal static class PluginTypePatch
{
- [HarmonyTargetMethods]
- public static IEnumerable TargetMethods()
- {
- yield return AccessTools.Method(typeof(MySession), "RegisterComponentsFromAssemblies");
- yield return AccessTools.Method(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init));
- }
-
+ [HarmonyPatch(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init))]
[HarmonyTranspiler]
- public static IEnumerable Transpiler(IEnumerable instructions, MethodBase original)
+ private static IEnumerable MetadataTranspiler(IEnumerable instructions, ILGenerator generator)
{
- //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)))
+ 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, wrapper),
+ new(OpCodes.Brfalse, regularPluginLabel),
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Ldloc, 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, continueLabel))
+ .SearchForward(b => b.opcode == OpCodes.Ldloca_S)
+ .AddLabels([continueLabel])
.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();
+ [HarmonyPatch(typeof(MySession), "RegisterComponentsFromAssemblies", typeof(Assembly), typeof(bool), typeof(MyModContext))]
+ [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;
+ }
}