rework plugin type patch
Some checks failed
Build / Compute Version (push) Successful in 25s
Build / Build Nuget package (CringePlugins) (push) Failing after 5m2s
Build / Build Nuget package (NuGet) (push) Failing after 4m44s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 5m24s
Build / Build Nuget package (SharedCringe) (push) Failing after 3m50s
Build / Build Launcher (push) Failing after 3m31s

This commit is contained in:
zznty
2024-12-30 04:11:18 +07:00
parent 7e9813d2a7
commit d4bf30a21c
2 changed files with 60 additions and 33 deletions

View File

@@ -18,7 +18,7 @@
<Publicize Include="Sandbox.Game:Sandbox.Engine.Platform.Game.set_DrawThread" /> <Publicize Include="Sandbox.Game:Sandbox.Engine.Platform.Game.set_DrawThread" />
<Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.form" /> <Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.form" />
<Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.RenderThread_SizeChanged" /> <Publicize Include="Sandbox.Game:Sandbox.MySandboxGame.RenderThread_SizeChanged" />
<Publicize Include="VRage.Render;VRage.Render11;VRage.Platform.Windows;VRage.Scripting" IncludeCompilerGeneratedMembers="false" /> <Publicize Include="VRage.Render;VRage.Render11;VRage.Platform.Windows;VRage.Scripting;Sandbox.Game" IncludeCompilerGeneratedMembers="false" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -3,7 +3,7 @@ using HarmonyLib;
using Sandbox.Game.World; using Sandbox.Game.World;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.Loader; using VRage.Game;
using VRage.Game.ObjectBuilder; using VRage.Game.ObjectBuilder;
using VRage.Plugins; using VRage.Plugins;
@@ -12,40 +12,67 @@ namespace CringeLauncher.Patches;
[HarmonyPatch] [HarmonyPatch]
internal static class PluginTypePatch internal static class PluginTypePatch
{ {
[HarmonyTargetMethods] [HarmonyPatch(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init))]
public static IEnumerable<MethodInfo> TargetMethods()
{
yield return AccessTools.Method(typeof(MySession), "RegisterComponentsFromAssemblies");
yield return AccessTools.Method(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.Init));
}
[HarmonyTranspiler] [HarmonyTranspiler]
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original) private static IEnumerable<CodeInstruction> MetadataTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{ {
//replaces plugin.GetType() with GetPluginType(plugin) return new CodeMatcher(instructions, generator)
var pve = AccessTools.Method(typeof(Assembly), nameof(Assembly.Load), [typeof(AssemblyName)]); .SearchForward(b => b.opcode == OpCodes.Ldloc_2)
var method = AccessTools.Method(typeof(object), nameof(GetType)); .Advance(-1)
var getter = AccessTools.PropertyGetter(typeof(MyPlugins), nameof(MyPlugins.Plugins)); .CreateLabel(out var regularPluginLabel)
.DeclareLocal(typeof(PluginWrapper), out var wrapper)
.DefineLabel(out var continueLabel)
var matcher = new CodeMatcher(instructions); .Insert(new(OpCodes.Ldloc_2),
new(OpCodes.Isinst, typeof(PluginWrapper)), new(OpCodes.Stloc, wrapper),
if (original.DeclaringType == typeof(MySession)) new(OpCodes.Ldloc, wrapper),
{ new(OpCodes.Brfalse, regularPluginLabel),
matcher = matcher new(OpCodes.Ldloc_0),
.SearchForward(b => b.Calls(pve)) new(OpCodes.Ldloc, wrapper),
.Set(OpCodes.Call, AccessTools.Method(typeof(PluginTypePatch), nameof(LoadAssembly))); new(OpCodes.Call,
} AccessTools.PropertyGetter(typeof(PluginWrapper), nameof(PluginWrapper.InstanceType))),
new(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Type), nameof(Type.Assembly))),
return matcher CodeInstruction.Call(typeof(MyGlobalTypeMetadata), nameof(MyGlobalTypeMetadata.RegisterAssembly),
.SearchForward(b => b.Calls(getter)) [typeof(Assembly)]),
.SearchForward(b => b.Calls(method)) new(OpCodes.Br, continueLabel))
.Set(OpCodes.Call, AccessTools.Method(typeof(PluginTypePatch), nameof(GetPluginType))) .SearchForward(b => b.opcode == OpCodes.Ldloca_S)
.AddLabels([continueLabel])
.InstructionEnumeration(); .InstructionEnumeration();
} }
//Assembly.Load is called in MySession.RegisterComponentsFromAssemblies. When patching, it uses the wrong context [HarmonyPatch(typeof(MySession), "RegisterComponentsFromAssemblies", typeof(Assembly), typeof(bool), typeof(MyModContext))]
//todo: maybe there's a better way to do this? [HarmonyPrefix]
private static Assembly LoadAssembly(AssemblyName name) => AssemblyLoadContext.GetLoadContext(typeof(Launcher).Assembly)!.LoadFromAssemblyName(name); private static bool RegisterComponentsPrefix(MySession __instance)
private static Type GetPluginType(IPlugin plugin) => plugin is PluginWrapper wrapper ? wrapper.InstanceType : plugin.GetType(); {
__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;
}
} }