Skip to content

Commit

Permalink
Fixed an issue with Il2CppInterop Assembly Resolving when Il2Cpp Pref…
Browse files Browse the repository at this point in the history
…ixing is used
  • Loading branch information
HerpDerpinstine committed Sep 5, 2024
1 parent bed7261 commit 2177062
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
28. Fixed an issue with MelonLaunchOptions failing to parse arguments if an `=` sign is used instead of a space
29. Fixed an issue with MelonLaunchOptions failing to parse options if a `-` prefix is used instead of `--`
30. Fixed an issue with Command Line Arguments not being logged
31. Fixed an issue with Il2CppInterop Assembly Resolving when Il2Cpp Prefixing is used

---

Expand Down
12 changes: 7 additions & 5 deletions MelonLoader/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,26 +173,28 @@ internal static void WelcomeMessage()
var archString = MelonUtils.IsGame32Bit() ? "x86" : "x64";
MelonLogger.MsgDirect($"Game Arch: {archString}");
MelonLogger.MsgDirect("------------------------------");
MelonLogger.MsgDirect($"CommandLine: {string.Join(" ", MelonLaunchOptions.CommandLineArgs)}");
MelonLogger.MsgDirect($"Command-Line: {string.Join(" ", MelonLaunchOptions.CommandLineArgs)}");
MelonLogger.MsgDirect("------------------------------");


MelonEnvironment.PrintEnvironment();
}


internal static void Quit()
{
MelonDebug.Msg("[ML Core] Received Quit from Support Module. Shutting down...");
MelonDebug.Msg("[ML Core] Received Quit Request! Shutting down...");

MelonPreferences.Save();

HarmonyInstance.UnpatchSelf();
bHapticsManager.Disconnect();

#if NET6_0_OR_GREATER
Fixes.Il2CppInteropFixes.Shutdown();
#endif

MelonLogger.Flush();
//MelonLogger.Close();

Thread.Sleep(200);

if (MelonLaunchOptions.Core.QuitFix)
Expand Down
185 changes: 184 additions & 1 deletion MelonLoader/Fixes/Il2CppInteropFixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
using HarmonyLib;
using System.IO;
using MelonLoader.Utils;
using Il2CppInterop.Generator.Contexts;
using AsmResolver.DotNet;

namespace MelonLoader.Fixes
{
Expand All @@ -24,6 +26,7 @@ namespace MelonLoader.Fixes
// reverts: https://github.com/BepInEx/Il2CppInterop/commit/18e58ef5db42a71d6012ab0387b107a4132101eb
internal unsafe static class Il2CppInteropFixes
{
private static Dictionary<RewriteGlobalContext, Dictionary<string, AssemblyRewriteContext>> _assemblyLookup = new();
private static Dictionary<IntPtr, Type> _typeLookup = new();

private static MethodInfo _getType;
Expand All @@ -47,6 +50,14 @@ internal unsafe static class Il2CppInteropFixes
private static MethodInfo _fixedFindAbstractMethods;
private static MethodInfo _emitObjectToPointer;
private static MethodInfo _emitObjectToPointer_Prefix;
private static MethodInfo _rewriteGlobalContext_AddAssemblyContext;
private static MethodInfo _rewriteGlobalContext_AddAssemblyContext_Postfix;
private static MethodInfo _rewriteGlobalContext_Dispose;
private static MethodInfo _rewriteGlobalContext_Dispose_Prefix;
private static MethodInfo _rewriteGlobalContext_GetNewAssemblyForOriginal;
private static MethodInfo _rewriteGlobalContext_GetNewAssemblyForOriginal_Prefix;
private static MethodInfo _rewriteGlobalContext_TryGetNewTypeForOriginal;
private static MethodInfo _rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix;

internal static void Install()
{
Expand All @@ -56,6 +67,7 @@ internal static void Install()
Type thisType = typeof(Il2CppInteropFixes);
Type classInjectorType = typeof(ClassInjector);
Type ilGeneratorEx = typeof(ILGeneratorEx);
Type rewriteGlobalContextType = typeof(RewriteGlobalContext);

Type injectorHelpersType = classInjectorType.Assembly.GetType("Il2CppInterop.Runtime.Injection.InjectorHelpers");
if (injectorHelpersType == null)
Expand Down Expand Up @@ -105,6 +117,26 @@ internal static void Install()
if (_get_IsByRef == null)
throw new Exception("Failed to get Type.IsByRef.get");

_rewriteGlobalContext_AddAssemblyContext = rewriteGlobalContextType.GetMethod("AddAssemblyContext",
BindingFlags.NonPublic | BindingFlags.Instance);
if (_rewriteGlobalContext_AddAssemblyContext == null)
throw new Exception("Failed to get RewriteGlobalContext.AddAssemblyContext");

_rewriteGlobalContext_Dispose = rewriteGlobalContextType.GetMethod("Dispose",
BindingFlags.Public | BindingFlags.Instance);
if (_rewriteGlobalContext_Dispose == null)
throw new Exception("Failed to get RewriteGlobalContext.Dispose");

_rewriteGlobalContext_GetNewAssemblyForOriginal = rewriteGlobalContextType.GetMethod("GetNewAssemblyForOriginal",
BindingFlags.Public | BindingFlags.Instance);
if (_rewriteGlobalContext_GetNewAssemblyForOriginal == null)
throw new Exception("Failed to get RewriteGlobalContext.GetNewAssemblyForOriginal");

_rewriteGlobalContext_TryGetNewTypeForOriginal = rewriteGlobalContextType.GetMethod("TryGetNewTypeForOriginal",
BindingFlags.Public | BindingFlags.Instance);
if (_rewriteGlobalContext_TryGetNewTypeForOriginal == null)
throw new Exception("Failed to get RewriteGlobalContext.TryGetNewTypeForOriginal");

_fixedFindType = thisType.GetMethod(nameof(FixedFindType), BindingFlags.NonPublic | BindingFlags.Static);
_fixedAddTypeToLookup = thisType.GetMethod(nameof(FixedAddTypeToLookup), BindingFlags.NonPublic | BindingFlags.Static);
_fixedIsByRef = thisType.GetMethod(nameof(FixedIsByRef), BindingFlags.NonPublic | BindingFlags.Static);
Expand All @@ -116,6 +148,10 @@ internal static void Install()
_isTypeSupported_Transpiler = thisType.GetMethod(nameof(IsTypeSupported_Transpiler), BindingFlags.NonPublic | BindingFlags.Static);
_convertMethodInfo_Transpiler = thisType.GetMethod(nameof(ConvertMethodInfo_Transpiler), BindingFlags.NonPublic | BindingFlags.Static);
_emitObjectToPointer_Prefix = thisType.GetMethod(nameof(EmitObjectToPointer_Prefix), BindingFlags.NonPublic | BindingFlags.Static);
_rewriteGlobalContext_AddAssemblyContext_Postfix = thisType.GetMethod(nameof(RewriteGlobalContext_AddAssemblyContext_Postfix), BindingFlags.NonPublic | BindingFlags.Static);
_rewriteGlobalContext_Dispose_Prefix = thisType.GetMethod(nameof(RewriteGlobalContext_Dispose_Prefix), BindingFlags.NonPublic | BindingFlags.Static);
_rewriteGlobalContext_GetNewAssemblyForOriginal_Prefix = thisType.GetMethod(nameof(RewriteGlobalContext_GetNewAssemblyForOriginal_Prefix), BindingFlags.NonPublic | BindingFlags.Static);
_rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix = thisType.GetMethod(nameof(RewriteGlobalContext_TryGetNewTypeForOriginal_Prefix), BindingFlags.NonPublic | BindingFlags.Static);

MelonDebug.Msg("Patching Il2CppInterop ClassInjector.SystemTypeFromIl2CppType...");
Core.HarmonyInstance.Patch(_systemTypeFromIl2CppType,
Expand Down Expand Up @@ -148,18 +184,57 @@ internal static void Install()
MelonDebug.Msg("Patching Il2CppInterop ILGeneratorEx.EmitObjectToPointer...");
Core.HarmonyInstance.Patch(_emitObjectToPointer,
new HarmonyMethod(_emitObjectToPointer_Prefix));

MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.AddAssemblyContext...");
Core.HarmonyInstance.Patch(_rewriteGlobalContext_AddAssemblyContext,
null, new HarmonyMethod(_rewriteGlobalContext_AddAssemblyContext_Postfix));

MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.Dispose...");
Core.HarmonyInstance.Patch(_rewriteGlobalContext_Dispose,
new HarmonyMethod(_rewriteGlobalContext_Dispose_Prefix));

MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.GetNewAssemblyForOriginal...");
Core.HarmonyInstance.Patch(_rewriteGlobalContext_GetNewAssemblyForOriginal,
new HarmonyMethod(_rewriteGlobalContext_GetNewAssemblyForOriginal_Prefix));

MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.TryGetNewTypeForOriginal...");
Core.HarmonyInstance.Patch(_rewriteGlobalContext_TryGetNewTypeForOriginal,
new HarmonyMethod(_rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix));
}
catch (Exception e)
{
MelonLogger.Error(e);
}
}

internal static void Shutdown()
{
if (_assemblyLookup != null)
{
if (_assemblyLookup.Count > 0)
{
foreach (Dictionary<string, AssemblyRewriteContext> dict in _assemblyLookup.Values)
dict.Clear();
_assemblyLookup.Clear();
}
_assemblyLookup = null;
}

if (_typeLookup != null)
{
if (_typeLookup.Count > 0)
_typeLookup.Clear();
_typeLookup = null;
}
}

private static bool FixedIsByRef(Type type)
=> type.IsByRef || type.IsPointer;
=> (type != null) && (type.IsByRef || type.IsPointer);

private static Type FixedFindType(string il2CppTypeFullName)
{
if (string.IsNullOrEmpty(il2CppTypeFullName))
return null;
Type returnType = Type.GetType($"Il2Cpp.{il2CppTypeFullName}");
if (returnType == null)
returnType = Type.GetType($"Il2Cpp{il2CppTypeFullName}");
Expand All @@ -170,6 +245,10 @@ private static Type FixedFindType(string il2CppTypeFullName)

private static void FixedAddTypeToLookup(Type type, IntPtr typePointer)
{
if ((type == null)
|| (typePointer == IntPtr.Zero))
return;

_injectorHelpers_AddTypeToLookup.Invoke(null, [type, typePointer]);

typePointer = IL2CPP.il2cpp_class_get_type(typePointer);
Expand All @@ -186,6 +265,9 @@ private static bool EmitObjectToPointer_Prefix(bool __7, ref bool __8)

private static bool RewriteType_Prefix(Type __0, ref Type __result)
{
if (__0 == null)
return true;

if (__0 == typeof(void*))
{
__result = __0;
Expand All @@ -195,6 +277,106 @@ private static bool RewriteType_Prefix(Type __0, ref Type __result)
return true;
}

private static void RewriteGlobalContext_AddAssemblyContext_Postfix(RewriteGlobalContext __instance,
AssemblyRewriteContext __1)
{
if ((__instance == null)
|| (__1 == null)
|| __1.OriginalAssembly == null)
return;

if (!_assemblyLookup.TryGetValue(__instance, out Dictionary<string, AssemblyRewriteContext> contexts)
|| (contexts == null))
contexts = _assemblyLookup[__instance] = new();

string assemblyName = __1.OriginalAssembly.Name;
if (string.IsNullOrEmpty(assemblyName))
return;

contexts[assemblyName] = __1;
//MelonDebug.Msg($"[RewriteGlobalContext] Added: {assemblyName}");
}

private static bool RewriteGlobalContext_Dispose_Prefix(RewriteGlobalContext __instance)
{
if ((__instance == null)
|| !_assemblyLookup.ContainsKey(__instance)
|| !_assemblyLookup.Remove(__instance, out Dictionary<string, AssemblyRewriteContext> contexts)
|| (contexts == null))
return true;

contexts.Clear();
return true;
}

private static bool RewriteGlobalContext_GetNewAssemblyForOriginal_Prefix(RewriteGlobalContext __instance,
AssemblyDefinition __0,
ref AssemblyRewriteContext __result)
{
if ((__instance == null)
|| (__0 == null)
|| !_assemblyLookup.TryGetValue(__instance, out Dictionary<string, AssemblyRewriteContext> contexts)
|| (contexts == null))
return true;

string assemblyName = __0.Name;
if (contexts.TryGetValue(assemblyName, out __result))
{
//MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}");
return false;
}

if (assemblyName.StartsWith("Il2Cpp"))
assemblyName = assemblyName.Remove(0, 6);
else
assemblyName = $"Il2Cpp{assemblyName}";

if (contexts.TryGetValue(assemblyName, out __result))
{
//MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}");
return false;
}

return true;
}

private static bool RewriteGlobalContext_TryGetNewTypeForOriginal_Prefix(RewriteGlobalContext __instance,
TypeDefinition __0,
ref TypeRewriteContext? __result)

Check warning on line 345 in MelonLoader/Fixes/Il2CppInteropFixes.cs

View workflow job for this annotation

GitHub Actions / build_nuget_package

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if ((__instance == null)
|| (__0 == null)
|| (__0.Module == null)
|| (__0.Module.Assembly == null)
|| !_assemblyLookup.TryGetValue(__instance, out Dictionary<string, AssemblyRewriteContext> contexts)
|| (contexts == null))
return true;

string assemblyName = __0.Module.Assembly.Name;
if (string.IsNullOrEmpty(assemblyName))
return false;

AssemblyRewriteContext rewriteContext = null;
if (contexts.TryGetValue(assemblyName, out rewriteContext))
{
//MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}");
__result = rewriteContext.TryGetContextForOriginalType(__0);
return false;
}

if (assemblyName.StartsWith("Il2Cpp"))
assemblyName = assemblyName.Remove(0, 6);
else
assemblyName = $"Il2Cpp{assemblyName}";
if (contexts.TryGetValue(assemblyName, out rewriteContext))
{
//MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}");
__result = rewriteContext.TryGetContextForOriginalType(__0);
return false;
}

return true;
}

private static bool SystemTypeFromIl2CppType_Prefix(Il2CppTypeStruct* __0, ref Type __result)
{
Expand Down Expand Up @@ -279,6 +461,7 @@ private static IEnumerable<CodeInstruction> SystemTypeFromIl2CppType_Transpiler(
found = true;
instruction.opcode = OpCodes.Call;
instruction.operand = _fixedFindType;

MelonDebug.Msg("Patched Il2CppInterop ClassInjector.SystemTypeFromIl2CppType -> Type.GetType");
}

Expand Down

0 comments on commit 2177062

Please sign in to comment.