diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0d01a2094..d2da10f66 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -180,7 +180,7 @@ jobs:
xcopy BaseLibs\net6 Output\Debug\x64\MelonLoader\net6\ /E /H /Y
echo.
echo Copying Dobby x64...
- xcopy BaseLibs\dobby_x64.dll Output\Debug\x64\dobby.dll*
+ xcopy BaseLibs\dobby_x64.dll Output\Debug\x64\MelonLoader\Dependencies\dobby.dll*
echo.
echo Copying documentation files...
copy NOTICE.txt Output\Debug\x64
@@ -189,6 +189,8 @@ jobs:
copy LICENSE.md Output\Debug\x64\MelonLoader\Documentation\
copy NOTICE.txt Output\Debug\x64\MelonLoader\Documentation\
copy README.md Output\Debug\x64\MelonLoader\Documentation\
+ del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Windows - x64
with:
@@ -224,7 +226,7 @@ jobs:
xcopy BaseLibs\net6 Output\Debug\x86\MelonLoader\net6\ /E /H /Y
echo.
echo Copying Dobby x86...
- xcopy BaseLibs\dobby_x86.dll Output\Debug\x86\dobby.dll*
+ xcopy BaseLibs\dobby_x86.dll Output\Debug\x86\MelonLoader\Dependencies\dobby.dll*
echo.
echo Copying documentation files...
copy NOTICE.txt Output\Debug\x86
@@ -233,6 +235,8 @@ jobs:
copy LICENSE.md Output\Debug\x86\MelonLoader\Documentation\
copy NOTICE.txt Output\Debug\x86\MelonLoader\Documentation\
copy README.md Output\Debug\x86\MelonLoader\Documentation\
+ del Output\Debug\x86\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Debug\x86\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Windows - x86
with:
@@ -268,7 +272,7 @@ jobs:
xcopy BaseLibs\net6 Output\Release\x64\MelonLoader\net6\ /E /H /Y
echo.
echo Copying Dobby x64...
- xcopy BaseLibs\dobby_x64.dll Output\Release\x64\dobby.dll*
+ xcopy BaseLibs\dobby_x64.dll Output\Release\x64\MelonLoader\Dependencies\dobby.dll*
echo.
echo Copying documentation files...
copy NOTICE.txt Output\Release\x64
@@ -277,6 +281,8 @@ jobs:
copy LICENSE.md Output\Release\x64\MelonLoader\Documentation\
copy NOTICE.txt Output\Release\x64\MelonLoader\Documentation\
copy README.md Output\Release\x64\MelonLoader\Documentation\
+ del Output\Release\x64\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Release\x64\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Windows - x64
with:
@@ -312,7 +318,7 @@ jobs:
xcopy BaseLibs\net6 Output\Release\x86\MelonLoader\net6\ /E /H /Y
echo.
echo Copying Dobby x86...
- xcopy BaseLibs\dobby_x86.dll Output\Release\x86\dobby.dll*
+ xcopy BaseLibs\dobby_x86.dll Output\Release\x86\MelonLoader\Dependencies\dobby.dll*
echo.
echo Copying documentation files...
copy NOTICE.txt Output\Release\x86
@@ -321,6 +327,8 @@ jobs:
copy LICENSE.md Output\Release\x86\MelonLoader\Documentation\
copy NOTICE.txt Output\Release\x86\MelonLoader\Documentation\
copy README.md Output\Release\x86\MelonLoader\Documentation\
+ del Output\Release\x86\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Release\x86\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Windows - x86
with:
@@ -362,6 +370,8 @@ jobs:
copy LICENSE.md Output\Debug\x64\MelonLoader\Documentation\
copy NOTICE.txt Output\Debug\x64\MelonLoader\Documentation\
copy README.md Output\Debug\x64\MelonLoader\Documentation\
+ del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Linux - x64
with:
@@ -403,6 +413,8 @@ jobs:
copy LICENSE.md Output\Release\x64\MelonLoader\Documentation\
copy NOTICE.txt Output\Release\x64\MelonLoader\Documentation\
copy README.md Output\Release\x64\MelonLoader\Documentation\
+ del Output\Release\x64\MelonLoader\net6\MelonStartScreen.dll
+ del Output\Release\x64\MelonLoader\net6\MelonStartScreen.deps.json
- uses: actions/upload-artifact@v4
name: Upload Zip | Linux - x64
with:
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index 8fad867a9..78042b0af 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -23,4 +23,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: MelonLoaderNuGetPackage
- path: MelonLoader/Output/Release/MelonLoader/LavaGang.MelonLoader.0.6.5.nupkg
\ No newline at end of file
+ path: MelonLoader/Output/Release/MelonLoader/LavaGang.MelonLoader.0.6.6.nupkg
\ No newline at end of file
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 000000000..e52ebba49
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,41 @@
+# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
+#
+# You can adjust the behavior by modifying this file.
+# For more information, see:
+# https://github.com/actions/stale
+name: Close inactive issues
+
+on:
+ schedule:
+ - cron: '4 20 * * *'
+ workflow_dispatch:
+
+permissions:
+ issues: write
+ pull-requests: write
+
+concurrency:
+ group: stale
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@main
+ with:
+ days-before-issue-stale: 120
+ days-before-issue-close: 14
+ stale-issue-message: "This issue is stale because it has been open for 4 months with no activity. If this is still an issue then please leave a comment, or else this will close in 2 weeks."
+ close-issue-message: "This issue was closed because it has been 2 weeks since being marked as stale."
+ days-before-pr-stale: -1
+ days-before-pr-close: -1
+ exempt-issue-labels: "Work-in-Progress,Planned,Improvement"
+ operations-per-run: 100
+ lock:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dessant/lock-threads@v5.0.1
+ with:
+ issue-inactive-days: '365'
+ issue-lock-reason: 'resolved'
+ process-only: 'issues'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4c377a40..da8e3655b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
| Versions: |
| - |
+| [v0.6.6](#v066) |
| [v0.6.5](#v065) |
| [v0.6.4](#v064) |
| [v0.6.3](#v063) |
@@ -37,6 +38,31 @@
---
+### v0.6.6
+
+1. Updated Il2CppInterop to 1.4.6-ci.579
+2. Implemented a RegisterTypeInIl2CppWithInterfaces attribute
+3. Implemented Recursive Melon Folders with extended UserLib Resolving
+4. Reimplemented NetFramework Variant of Cpp2IL as fallback
+5. Standardized Assembly Searching and Resolving to work on both Mono and Il2Cpp Games
+6. Temporarily removed Start Screen for being broken in most cases
+7. Modified Command-Line Argument Logging to show Internal Arguments Only
+8. Added UserLibs folders to Native Library Search Directories
+9. Moved `dobby.dll` to `MelonLoader\Dependencies`
+10. Moved Assembly Resolver Related Classes to `MelonLoader.Resolver` Namespace
+11. Moved `MonoLibrary` class to `MelonLoader.Utils` Namespace
+12. Removed Useless TODO Warning from Il2CppAssemblyGenerator
+13. Removed EOS Compatibility Layer for being Unneeded
+14. Fixed Regression with LemonMD5, LemonSHA256, and LemonSHA512
+15. Fixed an issue with older Cpp2IL versions causing a download failure
+16. Fixed an issue with Il2CppInterop not properly logging Trampoline Exceptions
+17. Fixed an issue with Il2Cpp Class Injection Attributes causing exceptions to be thrown on Mono games
+18. Fixed an issue with the Bootstrap not reading `--melonloader.basedir` correctly
+19. Fixed an issue with Loading `dobby.dll` in some rare cases
+20. Fixed an issue with Compatibility Layers getting Garbage Collected while still in use
+
+---
+
### v0.6.5
1. Updated Il2CppInterop to 1.4.6-ci.545
diff --git a/Dependencies/CompatibilityLayers/EOS/EOS.csproj b/Dependencies/CompatibilityLayers/EOS/EOS.csproj
deleted file mode 100644
index cc4d68bae..000000000
--- a/Dependencies/CompatibilityLayers/EOS/EOS.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- MelonLoader.CompatibilityLayers
- net35
- Latest
- true
- false
- false
- $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\CompatibilityLayers\
- true
- embedded
-
-
-
-
-
\ No newline at end of file
diff --git a/Dependencies/CompatibilityLayers/EOS/Module.cs b/Dependencies/CompatibilityLayers/EOS/Module.cs
deleted file mode 100644
index ff15413c0..000000000
--- a/Dependencies/CompatibilityLayers/EOS/Module.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using MelonLoader.Modules;
-using MelonLoader.NativeUtils;
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)]
-[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)]
-[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)]
-[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)]
-[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)]
-[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)]
-[assembly: Guid("5100810A-9842-4073-9658-E5841FDF9D73")]
-[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)]
-[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)]
-[assembly: MelonLoader.PatchShield]
-
-namespace MelonLoader.CompatibilityLayers
-{
- internal class EOS_Module : MelonModule
- {
- private delegate IntPtr LoadLibraryDetour(IntPtr path);
- private NativeHook _hookWin;
-
- public override void OnInitialize()
- {
- var platform = Environment.OSVersion.Platform;
- switch (platform)
- {
- case PlatformID.Win32S:
- case PlatformID.Win32Windows:
- case PlatformID.Win32NT:
- case PlatformID.WinCE:
- NativeLibrary lib = NativeLibrary.Load("kernel32");
- if (lib != null)
- {
- IntPtr loadLibraryWPtr = lib.GetExport("LoadLibraryW");
- if (loadLibraryWPtr != IntPtr.Zero)
- {
- IntPtr detourPtr = Marshal.GetFunctionPointerForDelegate((LoadLibraryDetour)DetourWin);
- _hookWin = new NativeHook(loadLibraryWPtr, detourPtr);
- _hookWin.Attach();
- }
- }
- break;
-
- case PlatformID.Unix:
- case PlatformID.MacOSX:
-
- // TO-DO
-
- // libdl.so.2
- // dlopen
-
- break;
- }
- }
-
- private IntPtr DetourWin(IntPtr path)
- {
- if (path == IntPtr.Zero)
- return _hookWin.Trampoline(path);
-
- var pathString = Marshal.PtrToStringUni(path);
- if (string.IsNullOrEmpty(pathString))
- return _hookWin.Trampoline(path);
-
- if (pathString.EndsWith("EOSOVH-Win64-Shipping.dll")
- || pathString.EndsWith("EOSOVH-Win32-Shipping.dll"))
- {
- _hookWin.Detach();
- return IntPtr.Zero;
- }
-
- return _hookWin.Trampoline(path);
- }
-
- ~EOS_Module()
- {
- _hookWin?.Detach();
- _hookWin = null;
- }
- }
-}
diff --git a/Dependencies/CompatibilityLayers/IPA/Module.cs b/Dependencies/CompatibilityLayers/IPA/Module.cs
index 9a8dcce16..018263c95 100644
--- a/Dependencies/CompatibilityLayers/IPA/Module.cs
+++ b/Dependencies/CompatibilityLayers/IPA/Module.cs
@@ -2,11 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using MelonLoader.MonoInternals;
using IllusionPlugin;
-using System.IO;
using IllusionInjector;
using MelonLoader.Modules;
+using MelonLoader.Resolver;
namespace MelonLoader.CompatibilityLayers
{
@@ -26,7 +25,7 @@ public override void OnInitialize()
};
Assembly base_assembly = typeof(IPA_Module).Assembly;
foreach (string assemblyName in assembly_list)
- MonoResolveManager.GetAssemblyResolveInfo(assemblyName).Override = base_assembly;
+ MelonAssemblyResolver.GetAssemblyResolveInfo(assemblyName).Override = base_assembly;
MelonAssembly.CustomMelonResolvers += Resolve;
}
diff --git a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs
index 6a0e9d428..0551542a4 100644
--- a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs
+++ b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs
@@ -3,8 +3,8 @@
using System.Linq;
using System.Reflection;
using MelonLoader.Modules;
-using MelonLoader.MonoInternals;
using ModHelper;
+using MelonLoader.Resolver;
namespace MelonLoader.CompatibilityLayers
{
@@ -24,7 +24,7 @@ public override void OnInitialize()
};
Assembly base_assembly = typeof(Muse_Dash_Mono_Module).Assembly;
foreach (string assemblyName in assembly_list)
- MonoResolveManager.GetAssemblyResolveInfo(assemblyName).Override = base_assembly;
+ MelonAssemblyResolver.GetAssemblyResolveInfo(assemblyName).Override = base_assembly;
MelonAssembly.CustomMelonResolvers += Resolve;
}
diff --git a/Dependencies/Il2CppAssemblyGenerator/Core.cs b/Dependencies/Il2CppAssemblyGenerator/Core.cs
index 573ce9031..2c6d1608c 100644
--- a/Dependencies/Il2CppAssemblyGenerator/Core.cs
+++ b/Dependencies/Il2CppAssemblyGenerator/Core.cs
@@ -7,6 +7,7 @@
using System.Reflection;
using JNISharp.NativeInterface;
using MelonLoader.Il2CppAssemblyGenerator.Packages;
+using MelonLoader.Il2CppAssemblyGenerator.Packages.Models;
using MelonLoader.Modules;
using MelonLoader.Utils;
@@ -20,7 +21,7 @@ internal class Core : MelonModule
internal static HttpClient webClient = null;
- internal static Packages.Cpp2IL cpp2il = null;
+ internal static ExecutablePackage cpp2il = null;
internal static Cpp2IL_StrippedCodeRegSupport cpp2il_scrs = null;
internal static Packages.Il2CppInterop il2cppinterop = null;
@@ -58,7 +59,13 @@ private static int Run()
if (!MelonLaunchOptions.Il2CppAssemblyGenerator.OfflineMode)
RemoteAPI.Contact();
- cpp2il = new Packages.Cpp2IL();
+ Cpp2IL cpp2IL_netcore = new Cpp2IL();
+ if (MelonUtils.IsWindows
+ && (cpp2IL_netcore.VersionSem < Cpp2IL.NetCoreMinVersion))
+ cpp2il = new Cpp2IL_NetFramework();
+ else
+ cpp2il = cpp2IL_netcore;
+
//cpp2il_scrs = new Cpp2IL_StrippedCodeRegSupport(cpp2il);
il2cppinterop = new Packages.Il2CppInterop();
diff --git a/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL.cs b/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL.cs
index 58472e221..2ef929497 100644
--- a/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL.cs
+++ b/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL.cs
@@ -21,9 +21,8 @@ namespace MelonLoader.Il2CppAssemblyGenerator.Packages
{
internal class Cpp2IL : Models.ExecutablePackage
{
- internal static SemVersion NetCoreMinVersion = SemVersion.Parse("2022.1.0-pre-release.17");
- private static SemVersion NewExecutionMinVersion = SemVersion.Parse("2022.0.999");
- private SemVersion VersionSem;
+ internal static SemVersion NetCoreMinVersion = SemVersion.Parse("2022.1.0-pre-release.18");
+ internal SemVersion VersionSem;
private string BaseFolder;
private static string ReleaseName =>
diff --git a/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL_NetFramework.cs b/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL_NetFramework.cs
new file mode 100644
index 000000000..f3ff1922e
--- /dev/null
+++ b/Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL_NetFramework.cs
@@ -0,0 +1,99 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Semver;
+
+namespace MelonLoader.Il2CppAssemblyGenerator.Packages
+{
+ internal class Cpp2IL_NetFramework : Models.ExecutablePackage
+ {
+ private static string ReleaseName => "Windows-Netframework472";
+ internal Cpp2IL_NetFramework()
+ {
+ Version = MelonLaunchOptions.Il2CppAssemblyGenerator.ForceVersion_Dumper;
+#if !DEBUG
+ if (string.IsNullOrEmpty(Version) || Version.Equals("0.0.0.0"))
+ Version = RemoteAPI.Info.ForceDumperVersion;
+#endif
+ if (string.IsNullOrEmpty(Version) || Version.Equals("0.0.0.0"))
+ Version = $"2022.1.0-pre-release.15";
+
+ Name = nameof(Cpp2IL);
+ Destination = Path.Combine(Core.BasePath, Name);
+ OutputFolder = Path.Combine(Destination, "cpp2il_out");
+
+ URL = $"https://github.com/SamboyCoding/{Name}/releases/download/{Version}/{Name}-{Version}-{ReleaseName}.zip";
+ ExeFilePath = Path.Combine(Destination, $"{Name}.exe");
+ FilePath = Path.Combine(Core.BasePath, $"{Name}_{Version}.zip");
+ }
+
+ internal override bool ShouldSetup()
+ => string.IsNullOrEmpty(Config.Values.DumperVersion)
+ || !Config.Values.DumperVersion.Equals(Version);
+
+ internal override void Cleanup() { }
+
+ internal override void Save()
+ => Save(ref Config.Values.DumperVersion);
+
+ internal override bool Execute()
+ {
+ if (SemVersion.Parse(Version) <= SemVersion.Parse("2022.0.999"))
+ return ExecuteOld();
+ return ExecuteNew();
+ }
+
+ private bool ExecuteNew()
+ {
+ if (Execute([
+ MelonDebug.IsEnabled() ? "--verbose" : string.Empty,
+
+ "--game-path",
+ "\"" + Path.GetDirectoryName(Core.GameAssemblyPath) + "\"",
+
+ "--exe-name",
+ "\"" + Process.GetCurrentProcess().ProcessName + "\"",
+
+ "--output-as",
+ "dummydll",
+
+ "--use-processor",
+ "attributeanalyzer",
+ "attributeinjector",
+ MelonLaunchOptions.Cpp2IL.CallAnalyzer ? "callanalyzer" : string.Empty,
+ MelonLaunchOptions.Cpp2IL.NativeMethodDetector ? "nativemethoddetector" : string.Empty,
+ //"deobfmap",
+ //"stablenamer",
+
+ ], false, new Dictionary() {
+ {"NO_COLOR", "1"}
+ }))
+ return true;
+
+ return false;
+ }
+
+ private bool ExecuteOld()
+ {
+ if (Execute([
+ MelonDebug.IsEnabled() ? "--verbose" : string.Empty,
+
+ "--game-path",
+ "\"" + Path.GetDirectoryName(Core.GameAssemblyPath) + "\"",
+
+ "--exe-name",
+ "\"" + Process.GetCurrentProcess().ProcessName + "\"",
+
+ "--skip-analysis",
+ "--skip-metadata-txts",
+ "--disable-registration-prompts"
+
+ ], false, new Dictionary() {
+ {"NO_COLOR", "1"}
+ }))
+ return true;
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Dependencies/Il2CppAssemblyGenerator/Packages/Models/ExecutablePackage.cs b/Dependencies/Il2CppAssemblyGenerator/Packages/Models/ExecutablePackage.cs
index c477d7903..67fb72fab 100644
--- a/Dependencies/Il2CppAssemblyGenerator/Packages/Models/ExecutablePackage.cs
+++ b/Dependencies/Il2CppAssemblyGenerator/Packages/Models/ExecutablePackage.cs
@@ -104,7 +104,7 @@ internal bool Execute(string[] args, bool parenthesize_args = true, Dictionary
+
+
+
+
+
Libs\Il2Cppmscorlib.dll
diff --git a/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs b/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs
index 60ad60927..06668b909 100644
--- a/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs
+++ b/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs
@@ -3,7 +3,6 @@
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
-using Il2CppInterop.Runtime.Runtime;
using System;
using System.Reflection;
@@ -28,6 +27,8 @@ public FieldInfo MethodBaseToIl2CppFieldInfo(MethodBase method)
public void RegisterTypeInIl2CppDomain(Type type, bool logSuccess)
=> ClassInjector.RegisterTypeInIl2Cpp(type, new() { LogSuccess = logSuccess });
+ public void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess)
+ => ClassInjector.RegisterTypeInIl2Cpp(type, new() { LogSuccess = logSuccess, Interfaces = interfaces });
public bool IsInheritedFromIl2CppObjectBase(Type type)
=> (type != null) && type.IsSubclassOf(typeof(Il2CppObjectBase));
diff --git a/Dependencies/SupportModules/Il2Cpp/Main.cs b/Dependencies/SupportModules/Il2Cpp/Main.cs
index bf4bf2ef2..49f65d0c1 100644
--- a/Dependencies/SupportModules/Il2Cpp/Main.cs
+++ b/Dependencies/SupportModules/Il2Cpp/Main.cs
@@ -3,19 +3,17 @@
using Il2CppInterop.Runtime.Startup;
using MelonLoader.Support.Preferences;
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
-using HarmonyLib;
using MelonLoader.CoreClrUtils;
using UnityEngine;
using Il2CppInterop.Common;
-using Il2CppInterop.Runtime.InteropTypes;
using Microsoft.Extensions.Logging;
using MelonLoader.Utils;
using System.IO;
+#pragma warning disable CS0618 // Type or member is obsolete
+
namespace MelonLoader.Support
{
internal static class Main
diff --git a/Dependencies/SupportModules/Mono/Mono.csproj b/Dependencies/SupportModules/Mono/Mono.csproj
index 7c8204b89..99ac434c8 100644
--- a/Dependencies/SupportModules/Mono/Mono.csproj
+++ b/Dependencies/SupportModules/Mono/Mono.csproj
@@ -10,6 +10,11 @@
true
embedded
+
+
+
+
+
Libs\UnityEngine.dll
diff --git a/Dependencies/SupportModules/SceneHandler.cs b/Dependencies/SupportModules/SceneHandler.cs
index e959f4b0c..01c4e45f5 100644
--- a/Dependencies/SupportModules/SceneHandler.cs
+++ b/Dependencies/SupportModules/SceneHandler.cs
@@ -5,6 +5,8 @@
using UnityEngine.Events;
#endif
+#pragma warning disable CA2013
+
namespace MelonLoader.Support
{
internal static class SceneHandler
diff --git a/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs b/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs
new file mode 100644
index 000000000..5a1c679d9
--- /dev/null
+++ b/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace MelonLoader
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class RegisterTypeInIl2CppWithInterfaces : Attribute //Naming violation?
+ {
+ internal static List registrationQueue = new List();
+ internal static bool ready;
+ internal bool LogSuccess = true;
+
+ internal Type[] Interfaces;
+ internal bool GetInterfacesFromType;
+
+ public RegisterTypeInIl2CppWithInterfaces()
+ {
+ GetInterfacesFromType = true;
+ }
+
+ public RegisterTypeInIl2CppWithInterfaces(bool logSuccess)
+ {
+ LogSuccess = logSuccess;
+ GetInterfacesFromType = true;
+ }
+
+ public RegisterTypeInIl2CppWithInterfaces(params Type[] interfaces)
+ {
+ Interfaces = interfaces;
+ }
+
+ public RegisterTypeInIl2CppWithInterfaces(bool logSuccess, params Type[] interfaces)
+ {
+ LogSuccess = logSuccess;
+ Interfaces = interfaces;
+ }
+
+ public static void RegisterAssembly(Assembly asm)
+ {
+ if (!MelonUtils.IsGameIl2Cpp())
+ return;
+
+ if (!ready)
+ {
+ registrationQueue.Add(asm);
+ return;
+ }
+
+ IEnumerable typeTbl = asm.GetValidTypes();
+ if ((typeTbl == null) || (typeTbl.Count() <= 0))
+ return;
+
+ foreach (Type type in typeTbl)
+ {
+ object[] attTbl = type.GetCustomAttributes(typeof(RegisterTypeInIl2CppWithInterfaces), false);
+ if ((attTbl == null) || (attTbl.Length <= 0))
+ continue;
+
+ RegisterTypeInIl2CppWithInterfaces att = (RegisterTypeInIl2CppWithInterfaces)attTbl[0];
+ if (att == null)
+ continue;
+
+ Type[] interfaceArr = att.GetInterfacesFromType
+ ? type.GetInterfaces()
+ : att.Interfaces;
+
+ InteropSupport.RegisterTypeInIl2CppDomainWithInterfaces(type,
+ interfaceArr,
+ att.LogSuccess);
+ }
+ }
+
+ internal static void SetReady()
+ {
+ ready = true;
+
+ if (registrationQueue == null)
+ return;
+
+ foreach (var asm in registrationQueue)
+ RegisterAssembly(asm);
+
+ registrationQueue = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MelonLoader/BackwardsCompatibility/Melon/AssemblyResolveInfo.cs b/MelonLoader/BackwardsCompatibility/Melon/AssemblyResolveInfo.cs
new file mode 100644
index 000000000..f4ab132f5
--- /dev/null
+++ b/MelonLoader/BackwardsCompatibility/Melon/AssemblyResolveInfo.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace MelonLoader.MonoInternals
+{
+ [Obsolete("MelonLoader.MonoInternals.AssemblyResolveInfo is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.AssemblyResolveInfo instead.")]
+ public class AssemblyResolveInfo : Resolver.AssemblyResolveInfo { }
+}
diff --git a/MelonLoader/BackwardsCompatibility/Melon/MonoLibrary.cs b/MelonLoader/BackwardsCompatibility/Melon/MonoLibrary.cs
new file mode 100644
index 000000000..e6cc27192
--- /dev/null
+++ b/MelonLoader/BackwardsCompatibility/Melon/MonoLibrary.cs
@@ -0,0 +1,11 @@
+#if !NET6_0_OR_GREATER
+
+using System;
+
+namespace MelonLoader.MonoInternals
+{
+ [Obsolete("MelonLoader.MonoInternals.MonoLibrary is Only Here for Compatibility Reasons. Please use MelonLoader.Utils.MonoLibrary instead.")]
+ public class MonoLibrary : Utils.MonoLibrary { }
+}
+
+#endif
\ No newline at end of file
diff --git a/MelonLoader/BackwardsCompatibility/Melon/MonoResolveManager.cs b/MelonLoader/BackwardsCompatibility/Melon/MonoResolveManager.cs
new file mode 100644
index 000000000..03c0ba138
--- /dev/null
+++ b/MelonLoader/BackwardsCompatibility/Melon/MonoResolveManager.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Reflection;
+
+namespace MelonLoader.MonoInternals
+{
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver instead.")]
+ public static class MonoResolveManager
+ {
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.AddSearchDirectory is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.AddSearchDirectory instead.")]
+ public static void AddSearchDirectory(string path, int priority = 0)
+ => Resolver.SearchDirectoryManager.Add(path, priority);
+
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.RemoveSearchDirectory is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.RemoveSearchDirectory instead.")]
+ public static void RemoveSearchDirectory(string path)
+ => Resolver.SearchDirectoryManager.Remove(path);
+
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.OnAssemblyLoadHandler is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.dOnAssemblyLoad instead.")]
+ public delegate void OnAssemblyLoadHandler(Assembly assembly);
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.OnAssemblyLoad is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.OnAssemblyLoad instead.")]
+ public static event OnAssemblyLoadHandler OnAssemblyLoad;
+ internal static void SafeInvoke_OnAssemblyLoad(Assembly assembly)
+ => OnAssemblyLoad?.Invoke(assembly);
+
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.OnAssemblyResolveHandler is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.dOnAssemblyResolve instead.")]
+ public delegate Assembly OnAssemblyResolveHandler(string name, Version version);
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.OnAssemblyLoad is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.OnAssemblyLoad instead.")]
+ public static event OnAssemblyResolveHandler OnAssemblyResolve;
+ internal static Assembly SafeInvoke_OnAssemblyResolve(string name, Version version)
+ => OnAssemblyResolve?.Invoke(name, version);
+
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.GetAssemblyResolveInfo is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.GetAssemblyResolveInfo instead.")]
+ public static AssemblyResolveInfo GetAssemblyResolveInfo(string name)
+ => (AssemblyResolveInfo)Resolver.AssemblyManager.GetInfo(name);
+
+ [Obsolete("MelonLoader.MonoInternals.MonoResolveManager.LoadInfoFromAssembly is Only Here for Compatibility Reasons. Please use MelonLoader.Resolver.MelonAssemblyResolver.LoadInfoFromAssembly instead.")]
+ public static void LoadInfoFromAssembly(Assembly assembly)
+ => Resolver.AssemblyManager.LoadInfo(assembly);
+ }
+}
diff --git a/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs b/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs
index 7113e4579..0f380aa48 100644
--- a/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs
+++ b/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs
@@ -1,7 +1,6 @@
using MelonLoader.Modules;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using MelonLoader.Utils;
@@ -13,12 +12,8 @@ public static class MelonCompatibilityLayer
private static List layers = new List()
{
- // Il2Cpp Unity Tls - No longer needed in CoreCLR
- // new MelonModule.Info(Path.Combine(baseDirectory, "Il2CppUnityTls.dll"), () => !MelonUtils.IsGameIl2Cpp()),
-
// Illusion Plugin Architecture
new MelonModule.Info(Path.Combine(baseDirectory, "IPA.dll"), MelonUtils.IsGameIl2Cpp),
- new MelonModule.Info(Path.Combine(baseDirectory, "EOS.dll"), () => !MelonUtils.IsWindows)
};
private static void CheckGameLayerWithPlatform(string name, Func shouldBeIgnored)
@@ -64,7 +59,7 @@ internal static void LoadModules()
continue;
MelonDebug.Msg($"Loading MelonModule '{m.fullPath}'");
- MelonModule.Load(m);
+ m.moduleGC = MelonModule.Load(m);
}
foreach (var file in Directory.GetFiles(baseDirectory))
diff --git a/MelonLoader/Core.cs b/MelonLoader/Core.cs
index 62e2946d6..56fa6a280 100644
--- a/MelonLoader/Core.cs
+++ b/MelonLoader/Core.cs
@@ -1,10 +1,6 @@
using System;
using System.Diagnostics;
using System.Reflection;
-using System.Security;
-using MelonLoader.InternalUtils;
-using MelonLoader.MonoInternals;
-using MelonLoader.Utils;
using System.IO;
using bHapticsLib;
using System.Threading;
@@ -21,7 +17,7 @@
namespace MelonLoader
{
- internal static class Core
+ internal static class Core
{
private static bool _success = true;
@@ -60,10 +56,6 @@ internal static int Initialize()
if (MelonUtils.IsUnderWineOrSteamProton())
Pastel.ConsoleExtensions.Disable();
-#if NET6_0_OR_GREATER
- Fixes.DotnetLoadFromManagedFolderFix.Install();
-#endif
-
Fixes.UnhandledException.Install(AppDomain.CurrentDomain);
Fixes.ServerCertificateValidation.Install();
Assertions.LemonAssertMapping.Setup();
@@ -72,32 +64,35 @@ internal static int Initialize()
BootstrapInterop.SetDefaultConsoleTitleWithGameName(UnityInformationHandler.GameName,
UnityInformationHandler.GameVersion);
+ MelonAssemblyResolver.Setup();
+
+#if NET6_0_OR_GREATER
+
+ if (MelonLaunchOptions.Core.UserWantsDebugger && MelonEnvironment.IsDotnetRuntime)
+ {
+ MelonLogger.Msg("[Init] User requested debugger, attempting to launch now...");
+ Debugger.Launch();
+ }
+
+ Environment.SetEnvironmentVariable("IL2CPP_INTEROP_DATABASES_LOCATION", MelonEnvironment.Il2CppAssembliesDirectory);
+
+#else
+
try
{
- if (!MonoLibrary.Setup()
- || !MonoResolveManager.Setup())
+ if (!MonoLibrary.Setup())
{
_success = false;
return 1;
}
}
- catch (SecurityException)
+ catch (Exception ex)
{
- MelonDebug.Msg("[MonoLibrary] Caught SecurityException, assuming not running under mono and continuing with init");
- }
- catch (MissingMethodException)
- {
- MelonDebug.Msg("[MonoLibrary] Caught MissingMethodException, assuming not running under mono and continuing with init");
- }
-
-#if NET6_0_OR_GREATER
- if (MelonLaunchOptions.Core.UserWantsDebugger && MelonEnvironment.IsDotnetRuntime)
- {
- MelonLogger.Msg("[Init] User requested debugger, attempting to launch now...");
- Debugger.Launch();
+ MelonDebug.Msg($"[MonoLibrary] Caught Exception: {ex}");
+ _success = false;
+ return 1;
}
- Environment.SetEnvironmentVariable("IL2CPP_INTEROP_DATABASES_LOCATION", MelonEnvironment.Il2CppAssembliesDirectory);
#endif
MonoMod.Logs.DebugLog.OnLog += (string source, DateTime time, MonoMod.Logs.LogLevel level, string message) => MelonDebug.Msg($"[MonoMod] [{source}] [{level}] {message}");
@@ -128,7 +123,8 @@ internal static int Initialize()
MelonCompatibilityLayer.LoadModules();
MelonHandler.LoadUserlibs(MelonEnvironment.UserLibsDirectory);
- MelonHandler.LoadMelonsFromDirectory(MelonEnvironment.PluginsDirectory);
+ MelonHandler.LoadMelonFolders(MelonEnvironment.PluginsDirectory);
+
MelonEvents.MelonHarmonyEarlyInit.Invoke();
MelonEvents.OnPreInitialization.Invoke();
@@ -157,14 +153,18 @@ internal static int Start()
return 1;
MelonEvents.OnPreModsLoaded.Invoke();
- MelonHandler.LoadMelonsFromDirectory(MelonEnvironment.ModsDirectory);
+ MelonHandler.LoadMelonFolders(MelonEnvironment.ModsDirectory);
MelonEvents.OnPreSupportModule.Invoke();
if (!SupportModule.Setup())
return 1;
AddUnityDebugLog();
+
+#if NET6_0_OR_GREATER
RegisterTypeInIl2Cpp.SetReady();
+ RegisterTypeInIl2CppWithInterfaces.SetReady();
+#endif
MelonEvents.MelonHarmonyInit.Invoke();
MelonEvents.OnApplicationStart.Invoke();
@@ -196,9 +196,13 @@ internal static void WelcomeMessage()
var archString = MelonUtils.IsGame32Bit() ? "x86" : "x64";
MelonLogger.MsgDirect($"Game Arch: {archString}");
MelonLogger.MsgDirect("------------------------------");
- MelonLogger.MsgDirect($"Command-Line: {string.Join(" ", MelonLaunchOptions.CommandLineArgs)}");
+ MelonLogger.MsgDirect("Command-Line: ");
+ foreach (var pair in MelonLaunchOptions.InternalArguments)
+ if (string.IsNullOrEmpty(pair.Value))
+ MelonLogger.MsgDirect($" {pair.Key}");
+ else
+ MelonLogger.MsgDirect($" {pair.Key} = {pair.Value}");
MelonLogger.MsgDirect("------------------------------");
-
MelonEnvironment.PrintEnvironment();
}
diff --git a/MelonLoader/Fixes/DotnetLoadFromManagedFolderFix.cs b/MelonLoader/Fixes/DotnetLoadFromManagedFolderFix.cs
deleted file mode 100644
index 0b3e69b52..000000000
--- a/MelonLoader/Fixes/DotnetLoadFromManagedFolderFix.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-#if NET6_0_OR_GREATER
-using MelonLoader.Utils;
-using System.IO;
-using System.Reflection;
-using System.Runtime.Loader;
-
-namespace MelonLoader.Fixes
-{
- internal static class DotnetLoadFromManagedFolderFix
- {
- //TODO Update for non-windows platforms in future, or when updating runtime
- private static readonly string OurRuntimeDir = Path.Combine(MelonEnvironment.OurRuntimeDirectory, "runtimes", "win", "lib", "net6.0");
-
- internal static void Install()
- {
- AssemblyLoadContext.Default.Resolving += OnResolve;
- }
-
- private static Assembly TryLoad(AssemblyLoadContext alc, string path)
- {
- if (File.Exists(path))
- {
- MelonDebug.Msg($"[DotnetManagedFolder] Loading from {path}...");
- return alc.LoadFromAssemblyPath(path);
- }
- return null;
- }
-
- private static Assembly OnResolve(AssemblyLoadContext alc, AssemblyName name)
- {
- var ret = TryFind(alc, name);
- if (ret == null)
- MelonDebug.Msg($"[DotnetManagedFolder] Failed to find {name.Name} in any of the known search directories");
- return ret;
- }
-
- internal static Assembly TryFind(AssemblyLoadContext alc, AssemblyName name)
- {
- // Redirect ModHandler to main MelonLoader dll (us)
- if (name.Name == "MelonLoader.ModHandler")
- return Assembly.GetExecutingAssembly();
-
- var ret = TryLoadFromFolders(alc, name.Name + ".dll");
- if (ret == null)
- TryLoadFromFolders(alc, name.Name + ".exe");
-
- return ret;
- }
-
- private static Assembly TryLoadFromFolders(AssemblyLoadContext alc, string filename)
- {
- var osSpecificPath = Path.Combine(OurRuntimeDir, filename);
- var il2cppPath = Path.Combine(MelonEnvironment.Il2CppAssembliesDirectory, filename);
- var managedPath = Path.Combine(MelonEnvironment.MelonManagedDirectory, filename);
- var modsPath = Path.Combine(MelonEnvironment.ModsDirectory, filename);
- var userlibsPath = Path.Combine(MelonEnvironment.UserLibsDirectory, filename);
- var gameRootPath = Path.Combine(MelonEnvironment.GameRootDirectory, filename);
- var runtimeSpecificPath = Path.Combine(MelonEnvironment.OurRuntimeDirectory, filename);
-
- var ret = TryLoad(alc, osSpecificPath)
- ?? TryLoad(alc, il2cppPath)
- ?? TryLoad(alc, managedPath)
- ?? TryLoad(alc, modsPath)
- ?? TryLoad(alc, userlibsPath)
- ?? TryLoad(alc, runtimeSpecificPath)
- ?? TryLoad(alc, gameRootPath);
-
- return ret;
- }
- }
-}
-#endif
\ No newline at end of file
diff --git a/MelonLoader/Fixes/Il2CppICallInjector.cs b/MelonLoader/Fixes/Il2CppICallInjector.cs
index 3269ab30e..54744971e 100644
--- a/MelonLoader/Fixes/Il2CppICallInjector.cs
+++ b/MelonLoader/Fixes/Il2CppICallInjector.cs
@@ -163,6 +163,30 @@ private static IntPtr il2cpp_resolve_icall_Detour(IntPtr signature)
return pair.Item3;
}
+ private static Type FindType(string typeFullName)
+ {
+ if (string.IsNullOrEmpty(typeFullName))
+ return null;
+
+ Type result = null;
+ foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ if (a == null)
+ continue;
+
+ result = a.GetValidType($"Il2Cpp.{typeFullName}");
+ if (result == null)
+ result = a.GetValidType($"Il2Cpp{typeFullName}");
+ if (result == null)
+ result = a.GetValidType(typeFullName);
+
+ if (result != null)
+ break;
+ }
+
+ return result;
+ }
+
private static bool ShouldInject(string signature, out MethodInfo unityShimMethod)
{
unityShimMethod = null;
@@ -172,7 +196,7 @@ private static bool ShouldInject(string signature, out MethodInfo unityShimMetho
string typeName = split[0];
// Find Managed Type
- Type newType = Il2CppInteropFixes.FixedFindType(typeName);
+ Type newType = FindType(typeName);
if (newType == null)
return false;
diff --git a/MelonLoader/Fixes/Il2CppInteropFixes.cs b/MelonLoader/Fixes/Il2CppInteropFixes.cs
index 73eed5036..ea58d70aa 100644
--- a/MelonLoader/Fixes/Il2CppInteropFixes.cs
+++ b/MelonLoader/Fixes/Il2CppInteropFixes.cs
@@ -17,6 +17,9 @@
using MelonLoader.Utils;
using Il2CppInterop.Generator.Contexts;
using AsmResolver.DotNet;
+using Il2CppInterop.HarmonySupport;
+
+#pragma warning disable CS8632
namespace MelonLoader.Fixes
{
@@ -26,6 +29,8 @@ namespace MelonLoader.Fixes
// fixes the rest of: https://github.com/BepInEx/Il2CppInterop/pull/134
internal unsafe static class Il2CppInteropFixes
{
+ private static MelonLogger.Instance _logger = new("Il2CppInterop");
+
private static Dictionary> _assemblyLookup = new();
private static Dictionary _typeLookup = new();
private static Dictionary _typeNameLookup = new();
@@ -59,6 +64,8 @@ internal unsafe static class Il2CppInteropFixes
private static MethodInfo _rewriteGlobalContext_GetNewAssemblyForOriginal_Prefix;
private static MethodInfo _rewriteGlobalContext_TryGetNewTypeForOriginal;
private static MethodInfo _rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix;
+ private static MethodInfo _reportException;
+ private static MethodInfo _reportException_Prefix;
internal static void Install()
{
@@ -70,11 +77,16 @@ internal static void Install()
Type ilGeneratorEx = typeof(ILGeneratorEx);
Type rewriteGlobalContextType = typeof(RewriteGlobalContext);
Type il2cppType = typeof(IL2CPP);
+ Type harmonySupportType = typeof(HarmonySupport);
Type injectorHelpersType = classInjectorType.Assembly.GetType("Il2CppInterop.Runtime.Injection.InjectorHelpers");
if (injectorHelpersType == null)
throw new Exception("Failed to get InjectorHelpers");
+ Type detourMethodPatcherType = harmonySupportType.Assembly.GetType("Il2CppInterop.HarmonySupport.Il2CppDetourMethodPatcher");
+ if (detourMethodPatcherType == null)
+ throw new Exception("Failed to get Il2CppDetourMethodPatcher");
+
_systemTypeFromIl2CppType = classInjectorType.GetMethod("SystemTypeFromIl2CppType", BindingFlags.NonPublic | BindingFlags.Static);
if (_systemTypeFromIl2CppType == null)
throw new Exception("Failed to get ClassInjector.SystemTypeFromIl2CppType");
@@ -137,7 +149,12 @@ internal static void Install()
_rewriteGlobalContext_TryGetNewTypeForOriginal = rewriteGlobalContextType.GetMethod("TryGetNewTypeForOriginal",
BindingFlags.Public | BindingFlags.Instance);
if (_rewriteGlobalContext_TryGetNewTypeForOriginal == null)
- throw new Exception("Failed to get RewriteGlobalContext.TryGetNewTypeForOriginal");
+ throw new Exception("Failed to get RewriteGlobalContext.TryGetNewTypeForOriginal");
+
+ _reportException = detourMethodPatcherType.GetMethod("ReportException",
+ BindingFlags.NonPublic | BindingFlags.Static);
+ if (_reportException == null)
+ throw new Exception("Failed to get Il2CppDetourMethodPatcher.ReportException");
_fixedFindType = thisType.GetMethod(nameof(FixedFindType), BindingFlags.NonPublic | BindingFlags.Static);
_fixedAddTypeToLookup = thisType.GetMethod(nameof(FixedAddTypeToLookup), BindingFlags.NonPublic | BindingFlags.Static);
@@ -154,6 +171,7 @@ internal static void Install()
_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);
+ _reportException_Prefix = thisType.GetMethod(nameof(ReportException_Prefix), BindingFlags.NonPublic | BindingFlags.Static);
MelonDebug.Msg("Patching Il2CppInterop ClassInjector.SystemTypeFromIl2CppType...");
Core.HarmonyInstance.Patch(_systemTypeFromIl2CppType,
@@ -202,6 +220,10 @@ internal static void Install()
MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.TryGetNewTypeForOriginal...");
Core.HarmonyInstance.Patch(_rewriteGlobalContext_TryGetNewTypeForOriginal,
new HarmonyMethod(_rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix));
+
+ MelonDebug.Msg("Patching Il2CppInterop Il2CppDetourMethodPatcher.ReportException...");
+ Core.HarmonyInstance.Patch(_reportException,
+ new HarmonyMethod(_reportException_Prefix));
}
catch (Exception e)
{
@@ -275,6 +297,13 @@ private static void FixedAddTypeToLookup(Type type, IntPtr typePointer)
_typeLookup.Add(typePointer, type);
}
+ private static bool ReportException_Prefix(Exception __0)
+ {
+ _logger.Error("During invoking native->managed trampoline", __0);
+
+ return false;
+ }
+
private static bool EmitObjectToPointer_Prefix(bool __7, ref bool __8)
{
__8 = __7;
diff --git a/MelonLoader/InternalUtils/DependencyGraph.cs b/MelonLoader/InternalUtils/DependencyGraph.cs
index db9b81f11..546fbdbaa 100644
--- a/MelonLoader/InternalUtils/DependencyGraph.cs
+++ b/MelonLoader/InternalUtils/DependencyGraph.cs
@@ -3,16 +3,10 @@
using System.Text;
using System.Reflection;
using System.IO;
+using MelonLoader.Resolver;
-#if NET35
-
-using MelonLoader.MonoInternals.ResolveInternals;
-
-#elif NET6_0_OR_GREATER
-
-using MelonLoader.Fixes;
+#if NET6_0_OR_GREATER
using System.Runtime.Loader;
-
#endif
namespace MelonLoader.InternalUtils
@@ -145,7 +139,12 @@ private static bool TryLoad(AssemblyName assembly)
{
try
{
- Assembly asm = Assembly.Load(assembly);
+#if NET6_0_OR_GREATER
+ var asm = AssemblyLoadContext.Default.LoadFromAssemblyName(assembly);
+#else
+ var asm = Assembly.Load(assembly);
+#endif
+
if (asm == null)
return false;
return true;
@@ -163,11 +162,7 @@ private static bool TryResolve(AssemblyName assembly)
{
try
{
-#if NET35
Assembly asm = SearchDirectoryManager.Scan(assembly.Name);
-#elif NET6_0_OR_GREATER
- Assembly asm = DotnetLoadFromManagedFolderFix.TryFind(AssemblyLoadContext.Default, assembly);
-#endif
if (asm == null)
return false;
return true;
diff --git a/MelonLoader/Lemons/Cryptography/LemonMD5.cs b/MelonLoader/Lemons/Cryptography/LemonMD5.cs
index 5e0b37ff8..475b655cd 100644
--- a/MelonLoader/Lemons/Cryptography/LemonMD5.cs
+++ b/MelonLoader/Lemons/Cryptography/LemonMD5.cs
@@ -6,14 +6,19 @@ namespace MelonLoader.Lemons.Cryptography
public class LemonMD5
{
private HashAlgorithm algorithm;
+ private static LemonMD5 static_algorithm = new();
- public LemonMD5()
+ public LemonMD5()
{
algorithm = (HashAlgorithm)CryptoConfig.CreateFromName("System.Security.Cryptography.MD5");
algorithm.SetHashSizeValue(256);
}
- public byte[] ComputeHash(byte[] buffer) => algorithm.ComputeHash(buffer);
+ public static byte[] ComputeMD5Hash(byte[] buffer) => static_algorithm.ComputeHash(buffer);
+ public static byte[] ComputeMD5Hash(byte[] buffer, int offset, int count) => static_algorithm.ComputeHash(buffer, offset, count);
+ public static byte[] ComputeMD5Hash(Stream inputStream) => static_algorithm.ComputeHash(inputStream);
+
+ public byte[] ComputeHash(byte[] buffer) => algorithm.ComputeHash(buffer);
public byte[] ComputeHash(byte[] buffer, int offset, int count) => algorithm.ComputeHash(buffer, offset, count);
public byte[] ComputeHash(Stream inputStream) => algorithm.ComputeHash(inputStream);
}
diff --git a/MelonLoader/Lemons/Cryptography/LemonSHA256.cs b/MelonLoader/Lemons/Cryptography/LemonSHA256.cs
index 91be6a6eb..be2ab6115 100644
--- a/MelonLoader/Lemons/Cryptography/LemonSHA256.cs
+++ b/MelonLoader/Lemons/Cryptography/LemonSHA256.cs
@@ -7,14 +7,19 @@ namespace MelonLoader.Lemons.Cryptography
public class LemonSHA256
{
private HashAlgorithm algorithm;
+ private static LemonSHA256 static_algorithm = new();
- public LemonSHA256()
+ public LemonSHA256()
{
algorithm = (HashAlgorithm)CryptoConfig.CreateFromName("System.Security.Cryptography.SHA256");
algorithm.SetHashSizeValue(256);
}
- public byte[] ComputeHash(byte[] buffer) => algorithm.ComputeHash(buffer);
+ public static byte[] ComputeSHA256Hash(byte[] buffer) => static_algorithm.ComputeHash(buffer);
+ public static byte[] ComputeSHA256Hash(byte[] buffer, int offset, int count) => static_algorithm.ComputeHash(buffer, offset, count);
+ public static byte[] ComputeSHA256Hash(Stream inputStream) => static_algorithm.ComputeHash(inputStream);
+
+ public byte[] ComputeHash(byte[] buffer) => algorithm.ComputeHash(buffer);
public byte[] ComputeHash(byte[] buffer, int offset, int count) => algorithm.ComputeHash(buffer, offset, count);
public byte[] ComputeHash(Stream inputStream) => algorithm.ComputeHash(inputStream);
}
diff --git a/MelonLoader/Lemons/Cryptography/LemonSHA512.cs b/MelonLoader/Lemons/Cryptography/LemonSHA512.cs
index 6bec548bb..fac019107 100644
--- a/MelonLoader/Lemons/Cryptography/LemonSHA512.cs
+++ b/MelonLoader/Lemons/Cryptography/LemonSHA512.cs
@@ -6,12 +6,17 @@ namespace MelonLoader.Lemons.Cryptography
public class LemonSHA512
{
private HashAlgorithm algorithm;
+ private static LemonSHA512 static_algorithm = new();
- public LemonSHA512()
+ public LemonSHA512()
{
algorithm = (HashAlgorithm)CryptoConfig.CreateFromName("System.Security.Cryptography.SHA512");
algorithm.SetHashSizeValue(512);
- }
+ }
+
+ public static byte[] ComputeSHA512Hash(byte[] buffer) => static_algorithm.ComputeHash(buffer);
+ public static byte[] ComputeSHA512Hash(byte[] buffer, int offset, int count) => static_algorithm.ComputeHash(buffer, offset, count);
+ public static byte[] ComputeSHA512Hash(Stream inputStream) => static_algorithm.ComputeHash(inputStream);
public byte[] ComputeHash(byte[] buffer) => algorithm.ComputeHash(buffer);
public byte[] ComputeHash(byte[] buffer, int offset, int count) => algorithm.ComputeHash(buffer, offset, count);
diff --git a/MelonLoader/MelonLaunchOptions.cs b/MelonLoader/MelonLaunchOptions.cs
index c1f413ba4..d10efc6dd 100644
--- a/MelonLoader/MelonLaunchOptions.cs
+++ b/MelonLoader/MelonLaunchOptions.cs
@@ -16,6 +16,7 @@ public static class MelonLaunchOptions
///
///
public static Dictionary ExternalArguments { get; private set; } = new Dictionary();
+ public static Dictionary InternalArguments { get; private set; } = new Dictionary();
///
/// Array of All Command Line Arguments
@@ -64,6 +65,7 @@ internal static void Load()
// Parse Argumentless Commands
if (WithoutArg.TryGetValue(noPrefixCmd, out Action withoutArgFunc))
{
+ InternalArguments.Add(noPrefixCmd, null);
withoutArgFunc();
continue;
}
@@ -90,6 +92,7 @@ internal static void Load()
// Parse Argument Commands
if (WithArg.TryGetValue(noPrefixCmd, out Action withArgFunc))
{
+ InternalArguments.Add(noPrefixCmd, cmdArg);
withArgFunc(cmdArg);
continue;
}
diff --git a/MelonLoader/MelonLoader.csproj b/MelonLoader/MelonLoader.csproj
index ebe4affbd..c7bf6d119 100644
--- a/MelonLoader/MelonLoader.csproj
+++ b/MelonLoader/MelonLoader.csproj
@@ -11,7 +11,7 @@
true
embedded
- 0.6.5
+ 0.6.6
LavaGang.MelonLoader
modding unity
https://github.com/LavaGang/MelonLoader
diff --git a/MelonLoader/MelonUtils.cs b/MelonLoader/MelonUtils.cs
index 51e15e9c0..5b43368a1 100644
--- a/MelonLoader/MelonUtils.cs
+++ b/MelonLoader/MelonUtils.cs
@@ -45,6 +45,7 @@ internal static void Setup(AppDomain domain)
if (!Directory.Exists(MelonEnvironment.UserLibsDirectory))
Directory.CreateDirectory(MelonEnvironment.UserLibsDirectory);
+ AddNativeDLLDirectory(MelonEnvironment.UserLibsDirectory);
MelonHandler.Setup();
UnityInformationHandler.Setup();
@@ -487,6 +488,21 @@ public static string GetFileProductName(string filepath)
return null;
}
+ public static void AddNativeDLLDirectory(string path)
+ {
+ if (!IsWindows && !IsUnix)
+ return;
+
+ path = Path.GetFullPath(path);
+ if (!Directory.Exists(path))
+ return;
+
+ string envName = IsWindows ? "PATH" : "LD_LIBRARY_PATH";
+ string envSep = IsWindows ? ";" : ":";
+ string envPaths = Environment.GetEnvironmentVariable(envName);
+ Environment.SetEnvironmentVariable(envName, $"{envPaths}{envSep}{path}");
+ }
+
internal static void SetupWineCheck()
{
if (IsUnix || IsMac)
diff --git a/MelonLoader/Melons/MelonAssembly.cs b/MelonLoader/Melons/MelonAssembly.cs
index 18449b19d..8806bdc03 100644
--- a/MelonLoader/Melons/MelonAssembly.cs
+++ b/MelonLoader/Melons/MelonAssembly.cs
@@ -290,7 +290,10 @@ public void LoadMelons()
}
}
+#if NET6_0_OR_GREATER
RegisterTypeInIl2Cpp.RegisterAssembly(Assembly);
+ RegisterTypeInIl2CppWithInterfaces.RegisterAssembly(Assembly);
+#endif
if (rottenMelons.Count != 0)
{
diff --git a/MelonLoader/Melons/MelonFolderHandler.cs b/MelonLoader/Melons/MelonFolderHandler.cs
new file mode 100644
index 000000000..49db61987
--- /dev/null
+++ b/MelonLoader/Melons/MelonFolderHandler.cs
@@ -0,0 +1,176 @@
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+
+namespace MelonLoader.Melons
+{
+ internal class MelonFolderHandler
+ {
+ internal static void Scan(string path) where T : MelonTypeBase
+ {
+ // Get Full Directory Path
+ path = Path.GetFullPath(path);
+
+ // Log Loading Message
+ var loadingMsg = $"Loading {MelonTypeBase.TypeName}s from '{path}'...";
+ MelonLogger.WriteSpacer();
+ MelonLogger.Msg(loadingMsg);
+
+ // Parse Folders
+ bool hasWroteLine = false;
+ List melonAssemblies = new();
+ ProcessFolder(path, ref hasWroteLine, ref melonAssemblies);
+
+ // Parse Queue
+ var melons = new List();
+ foreach (var asm in melonAssemblies)
+ {
+ // Load Melons from Assembly
+ asm.LoadMelons();
+
+ // Parse Loaded Melons
+ foreach (var m in asm.LoadedMelons)
+ {
+ // Validate Type
+ if (m is T t)
+ {
+ melons.Add(t);
+ continue;
+ }
+
+ // Log Failure
+ MelonLogger.Warning($"Failed to load Melon '{m.Info.Name}' from '{path}': The given Melon is a {m.MelonTypeName} and cannot be loaded as a {MelonTypeBase.TypeName}. Make sure it's in the right folder.");
+ }
+ }
+
+ // Log
+ if (hasWroteLine)
+ MelonLogger.WriteSpacer();
+
+ // Register and Sort Melons
+ MelonBase.RegisterSorted(melons);
+
+ // Log
+ if (hasWroteLine)
+ MelonLogger.WriteLine(Color.Magenta);
+
+ // Log Melon Count
+ var count = MelonTypeBase._registeredMelons.Count;
+ MelonLogger.Msg($"{count} {MelonTypeBase.TypeName.MakePlural(count)} loaded.");
+ if (MelonHandler.firstSpacer || (typeof(T) == typeof(MelonMod)))
+ MelonLogger.WriteSpacer();
+ MelonHandler.firstSpacer = true;
+ }
+
+ private static void LoadFolder(string path,
+ bool addToList,
+ ref bool hasWroteLine,
+ ref List melonAssemblies) where T : MelonTypeBase
+ {
+ // Get DLLs in Directory
+ var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly);
+ foreach (var f in files)
+ {
+ // Log
+ if (!hasWroteLine)
+ {
+ hasWroteLine = true;
+ MelonLogger.WriteLine(Color.Magenta);
+ }
+
+ // Load Assembly
+ var asm = MelonAssembly.LoadMelonAssembly(f, false);
+ if (asm == null)
+ continue;
+
+ // Queue Assembly for Melon Parsing
+ if (addToList)
+ melonAssemblies.Add(asm);
+ }
+ }
+
+ private static bool IsUserLibsFolder(string dirNameLower)
+ => dirNameLower.StartsWith("userlibs")
+ || dirNameLower.EndsWith("userlibs");
+
+ private static bool IsDisabledFolder(string path,
+ out string dirNameLower)
+ {
+ string dirName = new DirectoryInfo(path).Name;
+ dirNameLower = dirName.ToLowerInvariant();
+ return dirNameLower.StartsWith("disabled")
+ || dirNameLower.EndsWith("disabled")
+ || dirNameLower.StartsWith("old")
+ || dirNameLower.EndsWith("old");
+ }
+
+ private static void ProcessFolder(string path,
+ ref bool hasWroteLine,
+ ref List melonAssemblies) where T : MelonTypeBase
+ {
+ // Validate Path
+ if (!Directory.Exists(path))
+ return;
+
+ // Add Base Path to Resolver
+ Resolver.MelonAssemblyResolver.AddSearchDirectory(path);
+
+ // Get Directories
+ var directories = Directory.GetDirectories(path, "*", SearchOption.AllDirectories);
+
+ // Add Directories to Resolver
+ if ((directories != null) && (directories.Length > 0))
+ {
+ foreach (var dir in directories)
+ {
+ // Validate Path
+ if (!Directory.Exists(dir))
+ continue;
+
+ // Skip Disabled Folders
+ if (IsDisabledFolder(dir, out string dirNameLower))
+ continue;
+
+ // Load Assemblies
+ if (IsUserLibsFolder(dirNameLower))
+ MelonUtils.AddNativeDLLDirectory(dir);
+ Resolver.MelonAssemblyResolver.AddSearchDirectory(dir);
+ }
+
+ // Load UserLibs
+ foreach (var dir in directories)
+ {
+ // Validate Path
+ if (!Directory.Exists(dir))
+ continue;
+
+ // Skip Disabled Folders and any folders that doesn't end with or isn't equal to UserLibs
+ if (IsDisabledFolder(dir, out string dirNameLower)
+ || !IsUserLibsFolder(dirNameLower))
+ continue;
+
+ // Load Assemblies
+ LoadFolder(dir, false, ref hasWroteLine, ref melonAssemblies);
+ }
+
+ // Load Melons from Extended Folders
+ foreach (var dir in directories)
+ {
+ // Validate Path
+ if (!Directory.Exists(dir))
+ continue;
+
+ // Skip Disabled Folders
+ if (IsDisabledFolder(dir, out _))
+ continue;
+
+ // Load Melons from Extended Folder
+ LoadFolder(dir, true, ref hasWroteLine, ref melonAssemblies);
+ }
+ }
+
+ // Load Melons from Base Path
+ LoadFolder(path, true, ref hasWroteLine, ref melonAssemblies);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MelonLoader/Melons/MelonHandler.cs b/MelonLoader/Melons/MelonHandler.cs
index d0d230273..80725eaf7 100644
--- a/MelonLoader/Melons/MelonHandler.cs
+++ b/MelonLoader/Melons/MelonHandler.cs
@@ -4,6 +4,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
+using MelonLoader.Melons;
using MelonLoader.Utils;
namespace MelonLoader
@@ -31,7 +32,7 @@ internal static void Setup()
Directory.CreateDirectory(MelonEnvironment.ModsDirectory);
}
- private static bool firstSpacer = false;
+ internal static bool firstSpacer = false;
public static void LoadMelonsFromDirectory(string path) where T : MelonTypeBase
{
path = Path.GetFullPath(path);
@@ -42,7 +43,7 @@ public static void LoadMelonsFromDirectory(string path) where T : MelonTypeBa
bool hasWroteLine = false;
- var files = Directory.GetFiles(path, "*.dll");
+ var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly);
var melonAssemblies = new List();
foreach (var f in files)
{
@@ -101,9 +102,7 @@ public static void LoadUserlibs(string path)
MelonLogger.Msg(loadingMsg);
bool hasWroteLine = false;
-
- var files = Directory.GetFiles(path, "*.dll");
- var melonAssemblies = new List();
+ var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly);
foreach (var f in files)
{
if (!hasWroteLine)
@@ -112,14 +111,13 @@ public static void LoadUserlibs(string path)
MelonLogger.WriteLine(Color.Magenta);
}
- var asm = MelonAssembly.LoadMelonAssembly(f, false);
- if (asm == null)
- continue;
-
- melonAssemblies.Add(asm);
+ MelonAssembly.LoadMelonAssembly(f, false);
}
}
+ public static void LoadMelonFolders(string path) where T : MelonTypeBase
+ => MelonFolderHandler.Scan(path);
+
#region Obsolete Members
///
/// List of Plugins.
diff --git a/MelonLoader/Modules/MelonModule.cs b/MelonLoader/Modules/MelonModule.cs
index 46a46afb0..ee23a5f83 100644
--- a/MelonLoader/Modules/MelonModule.cs
+++ b/MelonLoader/Modules/MelonModule.cs
@@ -4,6 +4,10 @@
using System.Linq;
using System.Reflection;
+#if NET6_0_OR_GREATER
+using System.Runtime.Loader;
+#endif
+
namespace MelonLoader.Modules
{
///
@@ -53,7 +57,11 @@ internal static MelonModule Load(Info moduleInfo)
Assembly asm;
try
{
+#if NET6_0_OR_GREATER
+ asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(moduleInfo.fullPath);
+#else
asm = Assembly.LoadFrom(moduleInfo.fullPath);
+#endif
}
catch (Exception ex)
{
@@ -115,6 +123,7 @@ public class Info
public readonly string fullPath;
internal readonly Func shouldBeRemoved;
internal readonly Func shouldBeIgnored;
+ internal MelonModule moduleGC;
internal Info(string path, Func shouldBeIgnored = null, Func shouldBeRemoved = null)
{
diff --git a/MelonLoader/Properties/AssemblyInfo.cs b/MelonLoader/Properties/AssemblyInfo.cs
index 6d54a6130..3277cba2d 100644
--- a/MelonLoader/Properties/AssemblyInfo.cs
+++ b/MelonLoader/Properties/AssemblyInfo.cs
@@ -17,4 +17,5 @@
[assembly: InternalsVisibleTo("Il2CppAssemblyGenerator")]
[assembly: InternalsVisibleTo("Il2CppUnityTls")]
[assembly: InternalsVisibleTo("Il2Cpp")]
-[assembly: InternalsVisibleTo("MelonStartScreen")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("MelonStartScreen")]
+[assembly: InternalsVisibleTo("EOS")]
\ No newline at end of file
diff --git a/MelonLoader/Properties/BuildInfo.cs b/MelonLoader/Properties/BuildInfo.cs
index c2ea9782c..c6ff6b100 100644
--- a/MelonLoader/Properties/BuildInfo.cs
+++ b/MelonLoader/Properties/BuildInfo.cs
@@ -6,6 +6,6 @@ public static class BuildInfo
public const string Description = "MelonLoader";
public const string Author = "Lava Gang";
public const string Company = "discord.gg/2Wn3N2P";
- public const string Version = "0.6.5";
+ public const string Version = "0.6.6";
}
}
\ No newline at end of file
diff --git a/MelonLoader/MonoInternals/ResolveInternals/AssemblyManager.cs b/MelonLoader/Resolver/AssemblyManager.cs
similarity index 79%
rename from MelonLoader/MonoInternals/ResolveInternals/AssemblyManager.cs
rename to MelonLoader/Resolver/AssemblyManager.cs
index 2d97578c0..f0d9b583a 100644
--- a/MelonLoader/MonoInternals/ResolveInternals/AssemblyManager.cs
+++ b/MelonLoader/Resolver/AssemblyManager.cs
@@ -1,11 +1,18 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+
+#if NET6_0_OR_GREATER
+using System.Runtime.Loader;
+#else
using System.Runtime.CompilerServices;
+#endif
+
+#pragma warning disable CS8632
-namespace MelonLoader.MonoInternals.ResolveInternals
+namespace MelonLoader.Resolver
{
- internal static class AssemblyManager
+ internal class AssemblyManager
{
internal static Dictionary InfoDict = new Dictionary();
@@ -29,11 +36,6 @@ internal static AssemblyResolveInfo GetInfo(string name)
return InfoDict[name];
}
- private static Assembly Resolve(string requested_name, ushort major, ushort minor, ushort build, ushort revision, bool is_preload)
- {
- Version requested_version = new Version(major, minor, build, revision);
- return Resolve(requested_name, requested_version, is_preload);
- }
private static Assembly Resolve(string requested_name, Version requested_version, bool is_preload)
{
// Get Resolve Information Object
@@ -44,7 +46,7 @@ private static Assembly Resolve(string requested_name, Version requested_version
// Run Passthrough Events
if (assembly == null)
- assembly = MonoResolveManager.SafeInvoke_OnAssemblyResolve(requested_name, requested_version);
+ assembly = MelonAssemblyResolver.SafeInvoke_OnAssemblyResolve(requested_name, requested_version);
// Search Directories
if (is_preload && (assembly == null))
@@ -70,10 +72,30 @@ internal static void LoadInfo(Assembly assembly)
resolveInfo.SetVersionSpecific(assemblyName.Version, assembly);
// Run Passthrough Events
- MonoResolveManager.SafeInvoke_OnAssemblyLoad(assembly);
+ MelonAssemblyResolver.SafeInvoke_OnAssemblyLoad(assembly);
+ }
+
+#if NET6_0_OR_GREATER
+
+ private static Assembly? Resolve(AssemblyLoadContext alc, AssemblyName name)
+ => Resolve(name.Name, name.Version, true);
+
+ private static void InstallHooks()
+ {
+ AssemblyLoadContext.Default.Resolving += Resolve;
+ }
+
+#else
+
+ private static Assembly Resolve(string requested_name, ushort major, ushort minor, ushort build, ushort revision, bool is_preload)
+ {
+ Version requested_version = new Version(major, minor, build, revision);
+ return Resolve(requested_name, requested_version, is_preload);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private extern static void InstallHooks();
+
+#endif
}
}
diff --git a/MelonLoader/MonoInternals/AssemblyResolveInfo.cs b/MelonLoader/Resolver/AssemblyResolveInfo.cs
similarity index 94%
rename from MelonLoader/MonoInternals/AssemblyResolveInfo.cs
rename to MelonLoader/Resolver/AssemblyResolveInfo.cs
index 7cc1df4e9..eb975cfbc 100644
--- a/MelonLoader/MonoInternals/AssemblyResolveInfo.cs
+++ b/MelonLoader/Resolver/AssemblyResolveInfo.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Reflection;
-namespace MelonLoader.MonoInternals
+namespace MelonLoader.Resolver
{
public class AssemblyResolveInfo
{
@@ -17,7 +17,7 @@ internal Assembly Resolve(Version requested_version)
return Override;
// Check for Requested Version
- if ((requested_version != null)
+ if (requested_version != null
&& GetVersionSpecific(requested_version, out Assembly assembly))
return assembly;
diff --git a/MelonLoader/MonoInternals/MonoResolveManager.cs b/MelonLoader/Resolver/MelonAssemblyResolver.cs
similarity index 66%
rename from MelonLoader/MonoInternals/MonoResolveManager.cs
rename to MelonLoader/Resolver/MelonAssemblyResolver.cs
index 0d775be2b..d4062503a 100644
--- a/MelonLoader/MonoInternals/MonoResolveManager.cs
+++ b/MelonLoader/Resolver/MelonAssemblyResolver.cs
@@ -1,17 +1,22 @@
using System;
using System.IO;
using System.Reflection;
-using MelonLoader.MonoInternals.ResolveInternals;
using MelonLoader.Utils;
-namespace MelonLoader.MonoInternals
+#if NET6_0_OR_GREATER
+using System.Runtime.Loader;
+#endif
+
+#pragma warning disable CS0618 // Type or member is obsolete
+
+namespace MelonLoader.Resolver
{
- public static class MonoResolveManager
+ public class MelonAssemblyResolver
{
- internal static bool Setup()
+ internal static void Setup()
{
if (!AssemblyManager.Setup())
- return false;
+ return;
// Setup Search Directories
string[] searchdirlist =
@@ -22,10 +27,12 @@ internal static bool Setup()
MelonEnvironment.MelonBaseDirectory,
MelonEnvironment.GameRootDirectory,
MelonEnvironment.OurRuntimeDirectory,
+ MelonEnvironment.Il2CppAssembliesDirectory,
+ MelonEnvironment.UnityGameManagedDirectory,
};
foreach (string path in searchdirlist)
AddSearchDirectory(path);
-
+
ForceResolveRuntime("Mono.Cecil.dll");
ForceResolveRuntime("MonoMod.exe");
ForceResolveRuntime("MonoMod.Utils.dll");
@@ -37,13 +44,11 @@ internal static bool Setup()
"MelonLoader",
"MelonLoader.ModHandler",
};
- Assembly base_assembly = typeof(MonoResolveManager).Assembly;
+ Assembly base_assembly = typeof(MelonAssemblyResolver).Assembly;
foreach (string assemblyName in assembly_list)
GetAssemblyResolveInfo(assemblyName).Override = base_assembly;
- MelonDebug.Msg("[MonoResolveManager] Setup Successful!");
-
- return true;
+ MelonDebug.Msg("[MelonAssemblyResolver] Setup Successful!");
}
private static void ForceResolveRuntime(string fileName)
@@ -53,9 +58,16 @@ private static void ForceResolveRuntime(string fileName)
return;
Assembly assembly = null;
- try { assembly = Assembly.LoadFrom(filePath); }
+ try
+ {
+#if NET6_0_OR_GREATER
+ assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(filePath);
+#else
+ assembly = Assembly.LoadFrom(filePath);
+#endif
+ }
catch { assembly = null; }
-
+
if (assembly == null)
return;
@@ -72,12 +84,32 @@ public static void RemoveSearchDirectory(string path)
public delegate void OnAssemblyLoadHandler(Assembly assembly);
public static event OnAssemblyLoadHandler OnAssemblyLoad;
internal static void SafeInvoke_OnAssemblyLoad(Assembly assembly)
- => OnAssemblyLoad?.Invoke(assembly);
+ {
+#if !NET6_0_OR_GREATER
+ // Backwards Compatibility
+ MonoInternals.MonoResolveManager.SafeInvoke_OnAssemblyLoad(assembly);
+#endif
+ OnAssemblyLoad?.Invoke(assembly);
+ }
public delegate Assembly OnAssemblyResolveHandler(string name, Version version);
public static event OnAssemblyResolveHandler OnAssemblyResolve;
internal static Assembly SafeInvoke_OnAssemblyResolve(string name, Version version)
- => OnAssemblyResolve?.Invoke(name, version);
+ {
+#if NET6_0_OR_GREATER
+
+ return OnAssemblyResolve?.Invoke(name, version);
+
+#else
+
+ // Backwards Compatibility
+ var assembly = MonoInternals.MonoResolveManager.SafeInvoke_OnAssemblyResolve(name, version);
+ if (assembly == null)
+ assembly = OnAssemblyResolve?.Invoke(name, version);
+ return assembly;
+
+#endif
+ }
public static AssemblyResolveInfo GetAssemblyResolveInfo(string name)
=> AssemblyManager.GetInfo(name);
diff --git a/MelonLoader/MonoInternals/ResolveInternals/SearchDirectoryManager.cs b/MelonLoader/Resolver/SearchDirectoryManager.cs
similarity index 74%
rename from MelonLoader/MonoInternals/ResolveInternals/SearchDirectoryManager.cs
rename to MelonLoader/Resolver/SearchDirectoryManager.cs
index 1c08dbd1a..8f1ff4da9 100644
--- a/MelonLoader/MonoInternals/ResolveInternals/SearchDirectoryManager.cs
+++ b/MelonLoader/Resolver/SearchDirectoryManager.cs
@@ -1,11 +1,17 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
+
+#if NET6_0_OR_GREATER
+using System.Runtime.Loader;
+#else
+using System;
using System.Runtime.InteropServices;
+using MelonLoader.Utils;
+#endif
-namespace MelonLoader.MonoInternals.ResolveInternals
+namespace MelonLoader.Resolver
{
internal static class SearchDirectoryManager
{
@@ -60,18 +66,28 @@ internal static Assembly Scan(string requested_name)
while (enumerator.MoveNext())
{
string folderpath = enumerator.Current.Path;
+ if (folderpath.ContainsExtension()
+ || !Directory.Exists(folderpath))
+ continue;
string filepath = Directory.GetFiles(folderpath).Where(x =>
- !string.IsNullOrEmpty(x)
- && ((Path.GetExtension(x).ToLowerInvariant().Equals(".dll")
- && Path.GetFileName(x).Equals($"{requested_name}.dll"))
- || (Path.GetExtension(x).ToLowerInvariant().Equals(".exe")
- && Path.GetFileName(x).Equals($"{requested_name}.exe")))
+ (!string.IsNullOrEmpty(x)
+ && ((Path.GetExtension(x).ToLowerInvariant().Equals(".dll")
+ && Path.GetFileName(x).Equals($"{requested_name}.dll"))
+ || (Path.GetExtension(x).ToLowerInvariant().Equals(".exe")
+ && Path.GetFileName(x).Equals($"{requested_name}.exe"))))
).FirstOrDefault();
if (string.IsNullOrEmpty(filepath))
continue;
+ MelonDebug.Msg($"[MelonAssemblyResolver] Loading from {filepath}...");
+
+#if NET6_0_OR_GREATER
+
+ return AssemblyLoadContext.Default.LoadFromAssemblyPath(filepath);
+
+#else
IntPtr filePathPtr = Marshal.StringToHGlobalAnsi(filepath);
if (filePathPtr == IntPtr.Zero)
continue;
@@ -89,8 +105,10 @@ internal static Assembly Scan(string requested_name)
continue;
return MonoLibrary.CastManagedAssemblyPtr(assemblyReflectionPtr);
+#endif
}
+ MelonDebug.Msg($"[MelonAssemblyResolver] Failed to find {requested_name} in any of the known search directories");
return null;
}
diff --git a/MelonLoader/Utils/InteropSupport.cs b/MelonLoader/Utils/InteropSupport.cs
index 2d738ad73..dd11bab9e 100644
--- a/MelonLoader/Utils/InteropSupport.cs
+++ b/MelonLoader/Utils/InteropSupport.cs
@@ -13,6 +13,7 @@ public interface Interface
FieldInfo MethodBaseToIl2CppFieldInfo(MethodBase method);
int? GetIl2CppMethodCallerCount(MethodBase method);
void RegisterTypeInIl2CppDomain(Type type, bool logSuccess);
+ void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess);
IntPtr CopyMethodInfoStruct(IntPtr ptr);
}
internal static Interface SMInterface;
@@ -89,7 +90,9 @@ public static T Il2CppObjectPtrToIl2CppObject(IntPtr ptr)
return SMInterface.GetIl2CppMethodCallerCount(method);
}
- public static void RegisterTypeInIl2CppDomain(Type type) => RegisterTypeInIl2CppDomain(type, true);
+ public static void RegisterTypeInIl2CppDomain(Type type)
+ => RegisterTypeInIl2CppDomain(type, true);
+
public static void RegisterTypeInIl2CppDomain(Type type, bool logSuccess)
{
ValidateInterface();
@@ -98,6 +101,21 @@ public static void RegisterTypeInIl2CppDomain(Type type, bool logSuccess)
SMInterface.RegisterTypeInIl2CppDomain(type, logSuccess);
}
+ public static void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces)
+ => RegisterTypeInIl2CppDomainWithInterfaces(type, interfaces, true);
+
+ public static void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess)
+ {
+ ValidateInterface();
+ if (type == null)
+ throw new NullReferenceException("The type cannot be null.");
+ if (interfaces == null)
+ throw new NullReferenceException("The interfaces cannot be null.");
+ if (interfaces.Length <= 0)
+ throw new NullReferenceException("The interfaces cannot be empty.");
+ SMInterface.RegisterTypeInIl2CppDomainWithInterfaces(type, interfaces, logSuccess);
+ }
+
public static IntPtr CopyMethodInfoStruct(IntPtr ptr)
{
ValidateInterface();
diff --git a/MelonLoader/MonoInternals/MonoLibrary.cs b/MelonLoader/Utils/MonoLibrary.cs
similarity index 95%
rename from MelonLoader/MonoInternals/MonoLibrary.cs
rename to MelonLoader/Utils/MonoLibrary.cs
index 04107b73e..a6f4ba7cd 100644
--- a/MelonLoader/MonoInternals/MonoLibrary.cs
+++ b/MelonLoader/Utils/MonoLibrary.cs
@@ -1,9 +1,11 @@
-using System;
+#if !NET6_0_OR_GREATER
+
+using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-namespace MelonLoader.MonoInternals
+namespace MelonLoader.Utils
{
public class MonoLibrary
{
@@ -50,3 +52,4 @@ internal static bool Setup()
public dmono_assembly_get_object mono_assembly_get_object = null;
}
}
+#endif
\ No newline at end of file
diff --git a/README.md b/README.md
index f71e5b066..76636ac80 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,10 @@
MelonLoader is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/LavaGang/MelonLoader/blob/master/LICENSE.md) for the full License.
Third-party Libraries used as Source Code and/or bundled in Binary Form:
-- [Research Detours Package](https://github.com/microsoft/Detours) is licensed under the MIT License. See [LICENSE](https://github.com/LavaGang/MelonLoader/blob/master/Bootstrap/Base/MSDetours/LICENSE.md) for the full License.
+- [Dobby](https://github.com/jmpews/Dobby) is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/jmpews/Dobby/blob/master/LICENSE) for the full License.
+- [dobby-rs](https://github.com/RinLovesYou/dobby-rs) is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/RinLovesYou/dobby-rs/blob/master/LICENSE) for the full License.
+- [dobby-sys](https://github.com/RinLovesYou/dobby-sys) is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/RinLovesYou/dobby-sys/blob/master/LICENSE) for the full License.
+- [unity-rs](https://github.com/RinLovesYou/unity-rs) is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/RinLovesYou/unity-rs/blob/master/LICENSE.txt) for the full License.
- [Mono](https://github.com/Unity-Technologies/mono) is licensed under multiple licenses. See [LICENSE](https://github.com/Unity-Technologies/mono/blob/unity-master/LICENSE) for full details.
- [HarmonyX](https://github.com/BepInEx/HarmonyX) is licensed under the MIT License. See [LICENSE](https://github.com/BepInEx/HarmonyX/blob/master/LICENSE) for the full License.
- [MonoMod](https://github.com/MonoMod/MonoMod) is licensed under the MIT License. See [LICENSE](https://github.com/MonoMod/MonoMod/blob/master/LICENSE) for the full License.
diff --git a/Rust/Bootstrap/src/base_assembly/mono.rs b/Rust/Bootstrap/src/base_assembly/mono.rs
index 8923d78a5..1db090d48 100644
--- a/Rust/Bootstrap/src/base_assembly/mono.rs
+++ b/Rust/Bootstrap/src/base_assembly/mono.rs
@@ -42,7 +42,7 @@ pub fn init(runtime: &FerrexRuntime) -> Result<(), DynErr> {
//get the AssemblyManager class and grab some methods from it
let assemblymanager_class = melonloader_assembly.get_class(
- "MelonLoader.MonoInternals.ResolveInternals",
+ "MelonLoader.Resolver",
"AssemblyManager",
runtime,
)?;
diff --git a/Rust/Bootstrap/src/constants.rs b/Rust/Bootstrap/src/constants.rs
index ced7a3f1c..859912f66 100644
--- a/Rust/Bootstrap/src/constants.rs
+++ b/Rust/Bootstrap/src/constants.rs
@@ -18,7 +18,7 @@ pub type InvokeFnIl2Cpp = extern "C" fn(
pub type InitFnMono = extern "C" fn(*const c_char, *const c_char) -> *mut MonoDomain;
pub type InitFnIl2Cpp = extern "C" fn(*const c_char) -> *mut Il2CppDomain;
-pub const MELON_VERSION: &str = "0.6.5";
+pub const MELON_VERSION: &str = "0.6.6";
pub const IS_ALPHA: bool = false;
diff --git a/Rust/Bootstrap/src/icalls/mod.rs b/Rust/Bootstrap/src/icalls/mod.rs
index 9d58ef91d..70383934c 100644
--- a/Rust/Bootstrap/src/icalls/mod.rs
+++ b/Rust/Bootstrap/src/icalls/mod.rs
@@ -17,10 +17,10 @@ pub fn init(runtime: &FerrexRuntime) -> Result<(), DynErr> {
runtime.add_internal_call("MelonLoader.BootstrapInterop::NativeLogConsole", logger::log_console_interop as MethodPointer)?;
runtime.add_internal_call("MelonLoader.BootstrapInterop::NativeGetJavaVM", core_android::get_raw_java_vm as MethodPointer)?;
runtime.add_internal_call("MelonLoader.BootstrapInterop::NativeGetPackageName", paths::get_package_name_raw as MethodPointer)?;
- runtime.add_internal_call("MelonLoader.MonoInternals.MonoLibrary::GetLibPtr", mono_library::get_lib_ptr as MethodPointer)?;
- runtime.add_internal_call("MelonLoader.MonoInternals.MonoLibrary::CastManagedAssemblyPtr", mono_library::cast_assembly_ptr as MethodPointer)?;
- runtime.add_internal_call("MelonLoader.MonoInternals.MonoLibrary::GetRootDomainPtr", mono_library::get_domain_ptr as MethodPointer)?;
- runtime.add_internal_call("MelonLoader.MonoInternals.ResolveInternals.AssemblyManager::InstallHooks", resolve_internals::install_hooks as MethodPointer)?;
+ runtime.add_internal_call("MelonLoader.Utils.MonoLibrary::GetLibPtr", mono_library::get_lib_ptr as MethodPointer)?;
+ runtime.add_internal_call("MelonLoader.Utils.MonoLibrary::CastManagedAssemblyPtr", mono_library::cast_assembly_ptr as MethodPointer)?;
+ runtime.add_internal_call("MelonLoader.Utils.MonoLibrary::GetRootDomainPtr", mono_library::get_domain_ptr as MethodPointer)?;
+ runtime.add_internal_call("MelonLoader.Resolver.AssemblyManager::InstallHooks", resolve_internals::install_hooks as MethodPointer)?;
runtime.add_internal_call("MelonLoader.Support.Preload::GetManagedDirectory", preload::get_managed_dir as MethodPointer)?;
Ok(())