add unloading for mod assemblies

This commit is contained in:
zznty
2022-10-29 00:26:23 +07:00
parent 0035d12789
commit 7204815c0c
2 changed files with 87 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Loader;
using CringeLauncher.Utils;
using HarmonyLib;
using NLog;
using Sandbox.Game.World;
using VRage.Scripting;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class ModScriptCompilerPatch
{
private static ILogger Log = LogManager.GetCurrentClassLogger();
private static AssemblyLoadContext _context = new(null, true);
static ModScriptCompilerPatch()
{
MySession.OnUnloaded += OnUnloaded;
}
private static void OnUnloaded()
{
if (!_context.Assemblies.Any())
return;
Log.Info("Unloading mod scripts context");
_context.Unload();
_context = new(null, true);
}
private static MethodInfo TargetMethod()
{
return MethodTools.AsyncMethodBody(
AccessTools.Method(typeof(MyScriptCompiler), nameof(MyScriptCompiler.Compile)));
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var ins = instructions.ToList();
for (var i = 0; i < ins.Count; i++)
{
var instruction = ins[i];
if (instruction.Calls(AccessTools.Method(typeof(Assembly), nameof(Assembly.Load),
new[] { typeof(byte[]) })))
{
ins[i - 1] = new(OpCodes.Nop); // memStream toArray call
ins[i] = CodeInstruction.CallClosure((Stream assembly) => _context.LoadFromStream(assembly));
}
else if (instruction.Calls(AccessTools.Method(typeof(Assembly), nameof(Assembly.Load),
new[] { typeof(byte[]), typeof(byte[]) })))
{
ins[i - 4] = new(OpCodes.Nop); // memStream toArray calls
ins[i - 1] = new(OpCodes.Nop);
ins[i] = CodeInstruction.CallClosure((Stream assembly, Stream assemblySymbols) =>
_context.LoadFromStream(assembly, assemblySymbols));
}
}
return ins;
}
}