Skip to content

Commit cbd70eb

Browse files
authored
Automatically load all interop assemblies before loading plugins (#777)
Assemblies are often loaded on the il2cpp side but not on the mono side, causing confusion when using reflection. This will load all interop assemblies right before plugins are loaded, which should mostly avoid these issues at a low time cost of around 40ms.
1 parent 2a61b61 commit cbd70eb

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

Runtimes/Unity/BepInEx.Unity.IL2CPP/IL2CPPChainloader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ private static IntPtr OnInvokeMethod(IntPtr method, IntPtr obj, IntPtr parameter
9797

9898
unhook = true;
9999

100+
Il2CppInteropManager.PreloadInteropAssemblies();
101+
100102
Instance.Execute();
101103
}
102104
catch (Exception ex)

Runtimes/Unity/BepInEx.Unity.IL2CPP/Il2CppInteropManager.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using System.Security.Cryptography;
99
using System.Text;
1010
using System.Text.RegularExpressions;
11+
using System.Threading;
12+
using System.Threading.Tasks;
1113
using BepInEx.Configuration;
1214
using BepInEx.Logging;
1315
using BepInEx.Unity.Common;
@@ -88,6 +90,14 @@ static Il2CppInteropManager()
8890
.AppendLine("{BepInEx} - Path to the BepInEx folder.")
8991
.AppendLine("{ProcessName} - Name of the current process")
9092
.ToString());
93+
94+
private static readonly ConfigEntry<bool> PreloadIL2CPPInteropAssemblies = ConfigFile.CoreConfig.Bind(
95+
"IL2CPP", "PreloadIL2CPPInteropAssemblies",
96+
true,
97+
new StringBuilder()
98+
.AppendLine("Automatically load all interop assemblies right before loading plugins.")
99+
.AppendLine("Some plugins may not work properly without this, but it may cause issues in some games.")
100+
.ToString());
91101

92102
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("InteropManager");
93103

@@ -357,4 +367,32 @@ private static void RunIl2CppInteropGenerator(List<AssemblyDefinition> sourceAss
357367

358368
sourceAssemblies.Do(x => x.Dispose());
359369
}
370+
371+
internal static void PreloadInteropAssemblies()
372+
{
373+
if (!PreloadIL2CPPInteropAssemblies.Value)
374+
return;
375+
376+
var sw = Stopwatch.StartNew();
377+
378+
var files = Directory.EnumerateFiles(IL2CPPInteropAssemblyPath);
379+
var loaded = 0;
380+
Parallel.ForEach(files, file =>
381+
{
382+
if (!file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) return;
383+
if (file.Equals("netstandard.dll", StringComparison.OrdinalIgnoreCase)) return;
384+
if (file.Equals("Il2Cppnetstandard.dll", StringComparison.OrdinalIgnoreCase)) return;
385+
try
386+
{
387+
Assembly.LoadFrom(file);
388+
Interlocked.Increment(ref loaded);
389+
}
390+
catch (Exception e)
391+
{
392+
Logger.LogWarning($"Failed to preload {file} - {e}");
393+
}
394+
});
395+
396+
Logger.LogDebug($"Preloaded {loaded} interop assemblies in {sw.ElapsedMilliseconds}ms");
397+
}
360398
}

0 commit comments

Comments
 (0)