Skip to content

Commit

Permalink
Fixed Load Order Issues with Il2Cpp and Mono Support
Browse files Browse the repository at this point in the history
  • Loading branch information
HerpDerpinstine committed Feb 5, 2025
1 parent d1c65fb commit 79e8904
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
</ProjectReference>
<ProjectReference Include="..\..\..\Runtimes\Il2Cpp\Runtime.Il2Cpp\Runtime.Il2Cpp.csproj" Private="false" ExcludeAssets="all">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="..\..\..\Runtimes\Il2Cpp\Runtime.Il2Cpp.Shared\Runtime.Il2Cpp.Shared.csproj" Private="false" ExcludeAssets="all">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="..\..\..\Runtimes\Mono\Runtime.Mono\Runtime.Mono.csproj" Private="false" ExcludeAssets="all">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="..\..\..\Runtimes\Mono\Runtime.Mono.Shared\Runtime.Mono.Shared.csproj" Private="false" ExcludeAssets="all">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="..\Il2Cpp\Unity.Il2Cpp.AssemblyGenerator\Unity.Il2Cpp.AssemblyGenerator.csproj">
<Private>False</Private>
Expand Down
18 changes: 14 additions & 4 deletions Dependencies/Modules/Engines/Unity/Engine.Unity/UnityLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
using MelonLoader.Resolver;
using System.Runtime.Loader;
using MelonLoader.Engine.Unity.Il2Cpp;
using MelonLoader.Runtime.Mono;

namespace MelonLoader.Engine.Unity
{
internal class UnityLoaderModule : MelonEngineModule
{
private static readonly string GameDataPath = Path.Combine(MelonEnvironment.ApplicationRootDirectory, $"{MelonEnvironment.ApplicationExecutableName}_Data");
private static string LoaderPath;
private static string UnityPlayerPath;
private static string GameAssemblyPath;
private static string SupportModulePath;
private static bool IsIl2Cpp;

private static string LoaderPath;
private static string SupportModulePath;

public override bool Validate()
{
UnityPlayerPath = Path.Combine(MelonEnvironment.ApplicationRootDirectory, $"UnityPlayer{OsUtils.NativeFileExtension}");
Expand Down Expand Up @@ -97,7 +99,15 @@ public override void Initialize()
GameAssemblyPath = Path.Combine(MelonEnvironment.ApplicationRootDirectory, gameAssemblyName);
IsIl2Cpp = File.Exists(GameAssemblyPath);

string indentifier = IsIl2Cpp ? "Il2Cpp" : "Mono";
// Load Library
if (IsIl2Cpp)
Il2CppLibrary.Load(GameAssemblyPath);
else
{
MelonLogger.Error("UNITY MONO SUPPORT NOT IMPLEMENTED!");
}

string indentifier = IsIl2Cpp ? "Il2Cpp" : (MonoLibrary.IsBleedingEdge ? "MonoBleedingEdge" : "Mono");
SupportModulePath = Path.Combine(
LoaderPath,
IsIl2Cpp ? "net6" : "net35",
Expand All @@ -113,7 +123,7 @@ public override void Initialize()
Stage2();

// Initialize Il2Cpp Loader
Il2CppLoader.Initialize(this, new(GameAssemblyPath, SupportModulePath,
Il2CppLoader.Initialize(this, new(SupportModulePath,
[
"Internal_ActiveSceneChanged",
"UnityEngine.ISerializationCallbackReceiver.OnAfterSerialize"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Runtime.InteropServices;
using Il2CppInterop.HarmonySupport;
using HarmonyLib;
using MelonLoader.Runtime.Il2Cpp;

#pragma warning disable 0649

Expand All @@ -18,11 +19,7 @@ internal static class Il2CppICallInjector
{
private static Dictionary<string, (object, DynamicMethodDefinition, MethodInfo, IntPtr)> _lookup = new();

private delegate IntPtr dil2cpp_resolve_icall(IntPtr signature);
private static MelonNativeHook<dil2cpp_resolve_icall> il2cpp_resolve_icall_hook;

private delegate void dil2cpp_add_internal_call(IntPtr signature, IntPtr funcPtr);
private static dil2cpp_add_internal_call il2cpp_add_internal_call;
private static MelonNativeHook<Il2CppLibrary.dil2cpp_resolve_icall> il2cpp_resolve_icall_hook;

private static Type _il2CppDetourMethodPatcher;
private static MethodInfo _generateNativeToManagedTrampoline;
Expand All @@ -44,22 +41,9 @@ internal static unsafe void Install()
if (_generateNativeToManagedTrampoline == null)
throw new Exception("Failed to get Il2CppDetourMethodPatcher.GenerateNativeToManagedTrampoline");

string gameAssemblyName = "GameAssembly";
IntPtr gameAssemblyLib = MelonNativeLibrary.LoadLib(gameAssemblyName);
if (gameAssemblyLib == IntPtr.Zero)
throw new Exception($"Failed to load {gameAssemblyName} Native Library");

IntPtr il2cpp_resolve_icall = MelonNativeLibrary.GetExport(gameAssemblyLib, nameof(il2cpp_resolve_icall));
if (il2cpp_resolve_icall == IntPtr.Zero)
throw new Exception($"Failed to get {nameof(il2cpp_resolve_icall)} Native Export");

il2cpp_add_internal_call = MelonNativeLibrary.GetExport(gameAssemblyLib, nameof(il2cpp_add_internal_call)).GetDelegate<dil2cpp_add_internal_call>();
if (il2cpp_add_internal_call == null)
throw new Exception($"Failed to get {nameof(il2cpp_add_internal_call)} Native Export");

MelonDebug.Msg("Patching il2cpp_resolve_icall...");
IntPtr detourPtr = Marshal.GetFunctionPointerForDelegate((dil2cpp_resolve_icall)il2cpp_resolve_icall_Detour);
il2cpp_resolve_icall_hook = new MelonNativeHook<dil2cpp_resolve_icall>(il2cpp_resolve_icall, detourPtr);
IntPtr detourPtr = Marshal.GetFunctionPointerForDelegate((Il2CppLibrary.dil2cpp_resolve_icall)il2cpp_resolve_icall_Detour);
il2cpp_resolve_icall_hook = new MelonNativeHook<Il2CppLibrary.dil2cpp_resolve_icall>(Marshal.GetFunctionPointerForDelegate(Il2CppLibrary.Instance.il2cpp_resolve_icall), detourPtr);
il2cpp_resolve_icall_hook.Attach();
}
catch (Exception e)
Expand Down Expand Up @@ -146,7 +130,7 @@ private static IntPtr il2cpp_resolve_icall_Detour(IntPtr signature)

// Add New ICall to Il2Cpp Domain
_lookup[signatureStr] = pair;
il2cpp_add_internal_call(signature, pair.Item4);
Il2CppLibrary.Instance.il2cpp_add_internal_call(signature, pair.Item4);
LogMsg($"Registered mono icall {signatureStr} in il2cpp domain");

// Return New Function Pointer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
<ProjectReference Include="$(SolutionDir)\MelonLoader\MelonLoader.csproj" ExcludeAssets="all" Private="False">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Runtimes\Il2Cpp\Runtime.Il2Cpp.Shared\Runtime.Il2Cpp.Shared.csproj" Private="false" ExcludeAssets="all">
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AsmResolver.DotNet" Version="6.0.0-beta.1" ExcludeAssets="Runtime" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ namespace MelonLoader.Runtime.Il2Cpp
{
public class Il2CppLibrary
{
public static Il2CppLibrary Instance { get; private set; }
public static MelonNativeLibrary<Il2CppLibrary> Lib { get; private set; }
public static void Load(string filePath)
{
if (Instance != null)
return;

IntPtr libPtr = MelonNativeLibrary.LoadLib(filePath);
if (libPtr == IntPtr.Zero)
throw new Exception($"Failed to load {filePath}");

Lib = new(libPtr);
Instance = Lib.Instance;
}

#region Internal Call

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void dil2cpp_add_internal_call(IntPtr signature, IntPtr funcPtr);
public dil2cpp_add_internal_call il2cpp_add_internal_call;

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate IntPtr dil2cpp_resolve_icall(IntPtr signature);
public dil2cpp_resolve_icall il2cpp_resolve_icall;

#endregion

#region Il2Cpp Method

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ public unsafe static class Il2CppLoader
{
#region Private Members

private static Il2CppLibrary _lib;

private static MelonNativeDetour<Il2CppLibrary.d_il2cpp_runtime_invoke> il2cpp_runtime_invoke_detour;

#endregion
Expand All @@ -33,51 +31,30 @@ public static void Initialize(MelonEngineModule engineModule,
RuntimeInfo = runtimeInfo;

// Check if it found any Il2Cpp variant library
if (RuntimeInfo == null
|| string.IsNullOrEmpty(RuntimeInfo.LibPath))
if (RuntimeInfo == null)
{
MelonLogger.ThrowInternalFailure("Failed to find Il2Cpp Library!");
MelonLogger.ThrowInternalFailure("Invalid Runtime Info Passed!");
return;
}

// Load Library
if (!LoadLib())
return;

// Check Exports
if (!CheckExports())
return;

// Create il2cpp_runtime_invoke Detour
il2cpp_runtime_invoke_detour = new(_lib.il2cpp_runtime_invoke, h_il2cpp_runtime_invoke, false);
il2cpp_runtime_invoke_detour = new(Il2CppLibrary.Instance.il2cpp_runtime_invoke, h_il2cpp_runtime_invoke, false);

// Attach il2cpp_runtime_invoke Detour
MelonDebug.Msg($"Attaching il2cpp_runtime_invoke Detour...");
il2cpp_runtime_invoke_detour.Attach();
}

private static bool LoadLib()
{
// Load the Il2Cpp variant library
MelonDebug.Msg($"Loading Il2Cpp Library...");
_lib = new MelonNativeLibrary<Il2CppLibrary>(MelonNativeLibrary.LoadLib(RuntimeInfo.LibPath)).Instance;

// Check for Failure
if (_lib == null)
{
MelonLogger.ThrowInternalFailure($"Failed to load Il2Cpp Library from {RuntimeInfo.LibPath}!");
return false;
}

return true;
}

private static bool CheckExports()
{
Dictionary<string, Delegate> listOfExports = new();

listOfExports[nameof(_lib.il2cpp_method_get_name)] = _lib.il2cpp_method_get_name;
listOfExports[nameof(_lib.il2cpp_runtime_invoke)] = _lib.il2cpp_runtime_invoke;
listOfExports[nameof(Il2CppLibrary.Instance.il2cpp_method_get_name)] = Il2CppLibrary.Instance.il2cpp_method_get_name;
listOfExports[nameof(Il2CppLibrary.Instance.il2cpp_runtime_invoke)] = Il2CppLibrary.Instance.il2cpp_runtime_invoke;

foreach (var exportPair in listOfExports)
{
Expand All @@ -98,7 +75,7 @@ private static bool CheckExports()
private static IntPtr h_il2cpp_runtime_invoke(IntPtr method, IntPtr obj, void** param, ref IntPtr exc)
{
// Get Method Name
string methodName = _lib.il2cpp_method_get_name(method).ToAnsiString();
string methodName = Il2CppLibrary.Instance.il2cpp_method_get_name(method).ToAnsiString();

// Check for Trigger Method
foreach (string triggerMethod in RuntimeInfo.TriggerMethods)
Expand All @@ -113,7 +90,7 @@ private static IntPtr h_il2cpp_runtime_invoke(IntPtr method, IntPtr obj, void**
EngineModule.Stage3(RuntimeInfo.SupportModulePath);

// Return original Invoke without Trampoline
return _lib.il2cpp_runtime_invoke(method, obj, param, ref exc);
return Il2CppLibrary.Instance.il2cpp_runtime_invoke(method, obj, param, ref exc);
}

// Return original Invoke
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ public class Il2CppRuntimeInfo : MelonRuntimeInfo
#region Constructors

public Il2CppRuntimeInfo(
string libPath,
string supportModulePath,
string[] triggerMethods)
{
LibPath = libPath;
SupportModulePath = supportModulePath;
TriggerMethods = triggerMethods;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ namespace MelonLoader.Runtime.Mono
{
public class MonoLibrary
{
public static bool IsBleedingEdge { get; private set; } = true;

public static MonoLibrary Instance { get; private set; }
public static MelonNativeLibrary<MonoLibrary> Lib { get; private set; }
public static void Load(string filePath)
{
if (Instance != null)
return;

IntPtr libPtr = MelonNativeLibrary.LoadLib(filePath);
if (libPtr == IntPtr.Zero)
throw new Exception($"Failed to load {filePath}");

Lib = new(libPtr);
Instance = Lib.Instance;
}

#region Mono Method

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand Down
43 changes: 10 additions & 33 deletions Dependencies/Modules/Runtimes/Mono/Runtime.Mono/MonoLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ public unsafe static class MonoLoader
{
#region Private Members

private static MonoLibrary _lib;

private static MelonNativeDetour<MonoLibrary.d_mono_runtime_invoke> mono_runtime_invoke_detour;

#endregion
Expand All @@ -33,58 +31,37 @@ public static void Initialize(MelonEngineModule engineModule,
RuntimeInfo = runtimeInfo;

// Check if it found any Mono variant library
if (RuntimeInfo == null
|| string.IsNullOrEmpty(RuntimeInfo.LibPath))
if (RuntimeInfo == null)
{
MelonLogger.ThrowInternalFailure("Failed to find Mono Library!");
MelonLogger.ThrowInternalFailure("Invalid Runtime Info Passed!");
return;
}

// Load Library
if (!LoadLib())
return;

// Check Exports
if (!CheckExports())
return;

// Create mono_runtime_invoke Detour
mono_runtime_invoke_detour = new(_lib.mono_runtime_invoke, h_mono_runtime_invoke, false);
mono_runtime_invoke_detour = new(MonoLibrary.Instance.mono_runtime_invoke, h_mono_runtime_invoke, false);

// Attach mono_runtime_invoke Detour
MelonDebug.Msg($"Attaching mono_runtime_invoke Detour...");
mono_runtime_invoke_detour.Attach();
}

private static bool LoadLib()
{
// Load the Mono variant library
MelonDebug.Msg($"Loading Mono Library...");
_lib = new MelonNativeLibrary<MonoLibrary>(MelonNativeLibrary.LoadLib(RuntimeInfo.LibPath)).Instance;

// Check for Failure
if (_lib == null)
{
MelonLogger.ThrowInternalFailure($"Failed to load Il2Cpp Library from {RuntimeInfo.LibPath}!");
return false;
}

return true;
}

private static bool CheckExports()
{
Dictionary<string, Delegate> listOfExports = new();

listOfExports[nameof(_lib.mono_method_get_name)] = _lib.mono_method_get_name;
listOfExports[nameof(_lib.mono_runtime_invoke)] = _lib.mono_runtime_invoke;
listOfExports[nameof(MonoLibrary.Instance.mono_method_get_name)] = MonoLibrary.Instance.mono_method_get_name;
listOfExports[nameof(MonoLibrary.Instance.mono_runtime_invoke)] = MonoLibrary.Instance.mono_runtime_invoke;

foreach (var exportPair in listOfExports)
{
if (exportPair.Value != null)
continue;

MelonLogger.ThrowInternalFailure($"Failed to find {exportPair.Key} Export in Il2Cpp Library!");
MelonLogger.ThrowInternalFailure($"Failed to find {exportPair.Key} Export in Mono Library!");
return false;
}

Expand All @@ -98,7 +75,7 @@ private static bool CheckExports()
private static IntPtr h_mono_runtime_invoke(IntPtr method, IntPtr obj, void** param, ref IntPtr exc)
{
// Get Method Name
string methodName = _lib.mono_method_get_name(method).ToAnsiString();
string methodName = MonoLibrary.Instance.mono_method_get_name(method).ToAnsiString();

// Check for Trigger Method
foreach (string triggerMethod in RuntimeInfo.TriggerMethods)
Expand All @@ -109,11 +86,11 @@ private static IntPtr h_mono_runtime_invoke(IntPtr method, IntPtr obj, void** pa
// Detach mono_runtime_invoke Detour
mono_runtime_invoke_detour.Detach();

// Initiate Stage2
EngineModule.Stage2();
// Initiate Stage3
EngineModule.Stage3(RuntimeInfo.SupportModulePath);

// Return original Invoke without Trampoline
return _lib.mono_runtime_invoke(method, obj, param, ref exc);
return MonoLibrary.Instance.mono_runtime_invoke(method, obj, param, ref exc);
}

// Return original Invoke
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public class MonoRuntimeInfo : MelonRuntimeInfo
#region Constructors

public MonoRuntimeInfo(
string libPath,
string supportModulePath,
string[] triggerMethods)
{
LibPath = libPath;
{
SupportModulePath = supportModulePath;
TriggerMethods = triggerMethods;
}

Expand Down
Loading

0 comments on commit 79e8904

Please sign in to comment.