Skip to content

Commit

Permalink
Reimplemented Mono Runtime Support and NetStandard patches
Browse files Browse the repository at this point in the history
  • Loading branch information
HerpDerpinstine committed Feb 7, 2025
1 parent 612ac46 commit 636345b
Show file tree
Hide file tree
Showing 14 changed files with 837 additions and 78 deletions.
172 changes: 146 additions & 26 deletions Dependencies/Modules/Engines/Unity/Engine.Unity/UnityLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,44 @@
using System.Runtime.Loader;
using MelonLoader.Engine.Unity.Il2Cpp;
using MelonLoader.Runtime.Mono;
using System.Collections.Generic;

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

private static string LoaderPath;
private static string SupportModulePath;
private string LoaderPath;
private string SupportModulePath;

private MonoRuntimeInfo MonoInfo;

private static readonly string[] monoFolderNames =
[
"Mono",
"MonoBleedingEdge"
];

private static readonly string[] monoLibNames =
[
"mono",
#if WINDOWS
"mono-2.0-bdwgc",
"mono-2.0-sgen",
"mono-2.0-boehm"
#elif LINUX
"monobdwgc-2.0"
#endif
];

private static readonly string[] monoPosixHelperNames =
[
"MonoPosixHelper",
];

public override bool Validate()
{
Expand Down Expand Up @@ -48,35 +74,36 @@ public override void Initialize()

GameAssemblyPath = Path.Combine(MelonEnvironment.ApplicationRootDirectory, gameAssemblyName);
IsIl2Cpp = File.Exists(GameAssemblyPath);

// Load Library
if (IsIl2Cpp)
Il2CppLibrary.Load(GameAssemblyPath);
else
if (!IsIl2Cpp)
{
// Attempt to find Library

// Load Library
//MonoLibrary.Load(MonoLibPath);
// Android only has Il2Cpp currently
if (OsUtils.IsAndroid)
{
MelonLogger.ThrowInternalFailure($"Failed to find {gameAssemblyName}!");
return;
}

MelonLogger.Error("UNITY MONO SUPPORT NOT IMPLEMENTED!");
// Attempt to find Library
MonoInfo = GetMonoRuntimeInfo();
if (MonoInfo == null)
{
MelonLogger.ThrowInternalFailure("Failed to get Mono Runtime Info!");
return;
}
}

string indentifier = IsIl2Cpp ? "Il2Cpp" : (MonoLibrary.IsBleedingEdge ? "MonoBleedingEdge" : "Mono");
string indentifier = IsIl2Cpp ? "Il2Cpp" : (MonoInfo.IsBleedingEdge ? "MonoBleedingEdge" : "Mono");
SupportModulePath = Path.Combine(
LoaderPath,
IsIl2Cpp ? "net6" : "net35",
$"MelonLoader.Unity.{indentifier}.dll");
$"MelonLoader.Unity.{(IsIl2Cpp ? "Il2Cpp" : "Mono")}.dll");

SetEngineInfo("Unity", UnityInformationHandler.EngineVersion.ToStringWithoutType(), indentifier);
SetApplicationInfo(UnityInformationHandler.GameDeveloper, UnityInformationHandler.GameName, UnityInformationHandler.GameVersion);
SetEngineInfo("Unity", UnityInformationHandler.EngineVersion.ToStringWithoutType(), (IsIl2Cpp ? "Il2Cpp" : (MonoInfo.IsBleedingEdge ? "MonoBleedingEdge" : "Mono")));
SetApplicationInfo(UnityInformationHandler.GameName, UnityInformationHandler.GameDeveloper, UnityInformationHandler.GameVersion);
PrintAppInfo();

if (IsIl2Cpp)
{
// Run Stage2
Stage2();

// Initialize Il2Cpp Loader
Il2CppLoader.Initialize(this, new(SupportModulePath,
[
Expand All @@ -86,9 +113,13 @@ public override void Initialize()
}
else
{
MelonLogger.Error("UNITY MONO SUPPORT NOT IMPLEMENTED!");
Stage2();
Stage3(null);
// Android only has Il2Cpp currently
if (OsUtils.IsAndroid)
return;

// Initialize Mono Loader
MonoInfo.SupportModulePath = SupportModulePath;
MonoLoader.Initialize(this, MonoInfo);
}
}

Expand Down Expand Up @@ -141,5 +172,94 @@ public override void Stage3(string supportModulePath)
// Run Stage3 after Assembly Generation
base.Stage3(supportModulePath);
}

private MonoRuntimeInfo GetMonoRuntimeInfo()
{
// Folders the Mono folders might be located in
string[] directoriesToSearch =
[
MelonEnvironment.ApplicationRootDirectory,
GameDataPath
];

// Iterate through Variations in Mono types
(string, string, bool)? libPaths = null;
foreach (var folderName in monoFolderNames)
{
// Iterate through Variations in Mono Directory Positions
foreach (var dir in directoriesToSearch)
{
// Iterate through Variations in Mono Lib Names
string folderPath = Path.Combine(dir, folderName);
foreach (var fileName in monoLibNames)
{
libPaths = SearchFolderForMonoLib(folderPath, fileName);
if (libPaths != null)
break;
}
if (libPaths != null)
break;
}
if (libPaths != null)
break;
}
if (libPaths == null)
return null;

// Attempt to find Posix Helper
string posixPath = null;
foreach (string fileName in monoPosixHelperNames)
{
string localFileName = fileName;
if (OsUtils.IsUnix)
localFileName = $"lib{fileName}";
localFileName += OsUtils.NativeFileExtension;
string localFilePath = Path.Combine(libPaths.Value.Item1, localFileName);
if (File.Exists(localFilePath))
{
posixPath = localFilePath;
break;
}
}

bool isBleedingEdge = libPaths.Value.Item3;
return new MonoRuntimeInfo(libPaths.Value.Item2, posixPath, Path.Combine(GameDataPath, "Managed"), isBleedingEdge, null, [
(!isBleedingEdge ? "Awake" : string.Empty),
(!isBleedingEdge ? "DoSendMouseEvents" : string.Empty),
"Internal_ActiveSceneChanged",
"UnityEngine.ISerializationCallbackReceiver.OnAfterSerialize",
]);
}

private (string, string, bool)? SearchFolderForMonoLib(string folderPath, string fileName)
{
bool isBleedingEdge = (fileName != monoLibNames[0]);

if (OsUtils.IsUnix)
fileName = $"lib{fileName}";
fileName += OsUtils.NativeFileExtension;

string filePath = Path.Combine(folderPath, fileName);
if (File.Exists(filePath))
return (folderPath, filePath, isBleedingEdge);

string embedRuntimePath = Path.Combine(folderPath, "EmbedRuntime");
if (Directory.Exists(embedRuntimePath))
{
filePath = Path.Combine(embedRuntimePath, fileName);
if (File.Exists(filePath))
return (embedRuntimePath, filePath, isBleedingEdge);

string x64Path = Path.Combine(embedRuntimePath, "x86_64");
if (Directory.Exists(x64Path))
{
filePath = Path.Combine(x64Path, fileName);
if (File.Exists(filePath))
return (x64Path, filePath, isBleedingEdge);
}
}

return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ namespace MelonLoader.Runtime.Il2Cpp
{
public class Il2CppLibrary
{
#region Public Members

public static Il2CppLibrary Instance { get; private set; }
public static MelonNativeLibrary<Il2CppLibrary> Lib { get; private set; }

#endregion

#region Public Methods

public static void Load(string filePath)
{
if (Instance != null)
Expand All @@ -16,31 +23,45 @@ public static void Load(string filePath)
if (libPtr == IntPtr.Zero)
throw new Exception($"Failed to load {filePath}");

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

#region Internal Call
#endregion

#region Il2Cpp Domain

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate IntPtr d_il2cpp_init_version(IntPtr name, IntPtr version);
public d_il2cpp_init_version il2cpp_init_version { get; private set; }

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate IntPtr d_il2cpp_domain_get();
public d_il2cpp_domain_get il2cpp_domain_get { get; private set; }

#endregion

#region Il2Cpp Internal Calls

[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;
public dil2cpp_add_internal_call il2cpp_add_internal_call { get; private set; }

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate IntPtr dil2cpp_resolve_icall(IntPtr signature);
public dil2cpp_resolve_icall il2cpp_resolve_icall;
public dil2cpp_resolve_icall il2cpp_resolve_icall { get; private set; }

#endregion

#region Il2Cpp Method

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate IntPtr d_il2cpp_method_get_name(IntPtr method);
public d_il2cpp_method_get_name il2cpp_method_get_name;
public d_il2cpp_method_get_name il2cpp_method_get_name { get; private set; }

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public unsafe delegate IntPtr d_il2cpp_runtime_invoke(IntPtr method, IntPtr obj, void** param, ref IntPtr exc);
public d_il2cpp_runtime_invoke il2cpp_runtime_invoke;
public d_il2cpp_runtime_invoke il2cpp_runtime_invoke { get; private set; }

#endregion
}
Expand Down
Loading

0 comments on commit 636345b

Please sign in to comment.