diff --git a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/Engine.Unity.Shared.csproj b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/Engine.Unity.Shared.csproj
index c78f22723..0e2de1886 100644
--- a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/Engine.Unity.Shared.csproj
+++ b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/Engine.Unity.Shared.csproj
@@ -9,10 +9,6 @@
embedded
MelonLoader.Engine.Unity.Shared
-
-
-
-
diff --git a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/MelonCoroutines.cs b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/MelonCoroutines.cs
index cb1162a0d..3a78250f4 100644
--- a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/MelonCoroutines.cs
+++ b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/MelonCoroutines.cs
@@ -3,19 +3,23 @@
namespace MelonLoader
{
- internal abstract class MelonCoroutineInterop
+ public abstract class MelonCoroutineInterop
{
- internal abstract object Start(IEnumerator routine);
- internal abstract void Stop(object coroutineToken);
+ public abstract object Start(IEnumerator routine);
+ public abstract void Stop(object coroutineToken);
}
public static class MelonCoroutines
{
- internal static List QueuedCoroutines = new List();
- internal static MelonCoroutineInterop Interop;
+ private static List QueuedCoroutines = new List();
+ private static bool HasProcessedQueue;
+ public static MelonCoroutineInterop Interop;
- internal static void ProcessQueue()
+ public static void ProcessQueue()
{
+ if (HasProcessedQueue)
+ return;
+ HasProcessedQueue = true;
foreach (var queuedCoroutine in QueuedCoroutines)
Start(queuedCoroutine);
QueuedCoroutines.Clear();
@@ -31,6 +35,17 @@ public static object Start(IEnumerator routine)
{
if (Interop != null)
return Interop.Start(routine);
+ return Queue(routine);
+ }
+
+ ///
+ /// Start a new coroutine.
+ /// Coroutines are called at the end of the game Update loops.
+ ///
+ /// The target routine
+ /// An object that can be passed to Stop to stop this coroutine
+ public static object Queue(IEnumerator routine)
+ {
QueuedCoroutines.Add(routine);
return routine;
}
@@ -43,8 +58,14 @@ public static void Stop(object coroutineToken)
{
if (Interop != null)
Interop.Stop(coroutineToken);
- else
- QueuedCoroutines.Remove(coroutineToken as IEnumerator);
+ Dequeue(coroutineToken as IEnumerator);
+ }
+
+ public static void Dequeue(object coroutineToken)
+ {
+ IEnumerator routine = coroutineToken as IEnumerator;
+ if (QueuedCoroutines.Contains(routine))
+ QueuedCoroutines.Remove(routine);
}
}
}
\ No newline at end of file
diff --git a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/UnityInformationHandler.cs b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/UnityInformationHandler.cs
index 91b1e4b81..8e4b8e383 100644
--- a/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/UnityInformationHandler.cs
+++ b/Dependencies/Modules/Engines/Unity/Engine.Unity.Shared/UnityInformationHandler.cs
@@ -37,7 +37,7 @@ private static UnityVersion TryParse(string version)
return returnval;
}
- internal static void Setup(string gameDataPath, string unityPlayerPath)
+ public static void Setup(string gameDataPath, string unityPlayerPath)
{
//if (!string.IsNullOrEmpty(LoaderConfig.Current.UnityEngine.VersionOverride))
// EngineVersion = TryParse(LoaderConfig.Current.UnityEngine.VersionOverride);
diff --git a/Dependencies/Modules/Engines/Unity/Il2Cpp/Unity.Il2Cpp/Il2CppCoroutineInterop.cs b/Dependencies/Modules/Engines/Unity/Il2Cpp/Unity.Il2Cpp/Il2CppCoroutineInterop.cs
index 23c87057d..dbe18c0c4 100644
--- a/Dependencies/Modules/Engines/Unity/Il2Cpp/Unity.Il2Cpp/Il2CppCoroutineInterop.cs
+++ b/Dependencies/Modules/Engines/Unity/Il2Cpp/Unity.Il2Cpp/Il2CppCoroutineInterop.cs
@@ -10,21 +10,20 @@ internal class Il2CppCoroutineInterop : MelonCoroutineInterop
internal Il2CppCoroutineInterop(Il2CppSupportComponent component)
=> Component = component;
- internal override object Start(IEnumerator coroutine)
+ public override object Start(IEnumerator coroutine)
{
if (Component != null)
return Component.StartCoroutine(new Il2CppSystem.Collections.IEnumerator(new Il2CppEnumeratorWrapper(coroutine).Pointer));
-
- MelonCoroutines.QueuedCoroutines.Add(coroutine);
+ MelonCoroutines.Queue(coroutine);
return coroutine;
}
- internal override void Stop(object coroutineToken)
+ public override void Stop(object coroutineToken)
{
if (Component != null)
Component.StopCoroutine(coroutineToken as Coroutine);
else
- MelonCoroutines.QueuedCoroutines.Remove(coroutineToken as IEnumerator);
+ MelonCoroutines.Dequeue(coroutineToken);
}
}
}
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Libs/UnityEngine.dll b/Dependencies/Modules/Engines/Unity/Mono/Libs/UnityEngine.dll
new file mode 100644
index 000000000..571442868
Binary files /dev/null and b/Dependencies/Modules/Engines/Unity/Mono/Libs/UnityEngine.dll differ
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoCoroutineInterop.cs b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoCoroutineInterop.cs
new file mode 100644
index 000000000..1a3c27937
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoCoroutineInterop.cs
@@ -0,0 +1,28 @@
+using System.Collections;
+using UnityEngine;
+
+namespace MelonLoader.Engine.Unity.Mono
+{
+ internal class MonoCoroutineInterop : MelonCoroutineInterop
+ {
+ private MonoSupportComponent Component;
+
+ internal MonoCoroutineInterop(MonoSupportComponent component)
+ => Component = component;
+
+ public override object Start(IEnumerator coroutine)
+ {
+ if (Component != null)
+ return Component.StartCoroutine(coroutine);
+ return MelonCoroutines.Start(coroutine);
+ }
+
+ public override void Stop(object coroutineToken)
+ {
+ if (Component != null)
+ Component.StopCoroutine(coroutineToken as Coroutine);
+ else
+ MelonCoroutines.Stop(coroutineToken);
+ }
+ }
+}
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSceneHandler.cs b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSceneHandler.cs
new file mode 100644
index 000000000..fd9cc9236
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSceneHandler.cs
@@ -0,0 +1,100 @@
+using System;
+using UnityEngine.SceneManagement;
+using System.Collections.Generic;
+
+namespace MelonLoader.Engine.Unity.Mono
+{
+ internal class MonoSceneHandler : IDisposable
+ {
+ private MonoSupportModule SupportModule;
+
+ internal class SceneInitEvent
+ {
+ internal int buildIndex;
+ internal string name;
+ internal bool wasLoadedThisTick;
+ }
+ private Queue scenesLoaded = new Queue();
+
+ internal MonoSceneHandler(MonoSupportModule supportModule)
+ {
+ SupportModule = supportModule;
+
+ try
+ {
+ SceneManager.sceneLoaded += OnSceneLoad;
+ }
+ catch (Exception ex) { MelonLogger.Error($"SceneManager.sceneLoaded override failed: {ex}"); }
+
+ try
+ {
+ SceneManager.sceneUnloaded += OnSceneUnload;
+ }
+ catch (Exception ex) { MelonLogger.Error($"SceneManager.sceneUnloaded override failed: {ex}"); }
+ }
+
+ ~MonoSceneHandler()
+ => Dispose();
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2013:Do not use ReferenceEquals with value types")]
+ public void Dispose()
+ {
+ try
+ {
+ SceneManager.sceneLoaded -= OnSceneLoad;
+ }
+ catch (Exception ex) { MelonLogger.Error($"SceneManager.sceneLoaded override failed: {ex}"); }
+
+ try
+ {
+ SceneManager.sceneUnloaded -= OnSceneUnload;
+ }
+ catch (Exception ex) { MelonLogger.Error($"SceneManager.sceneUnloaded override failed: {ex}"); }
+ }
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2013:Do not use ReferenceEquals with value types")]
+ private void OnSceneLoad(Scene scene, LoadSceneMode mode)
+ {
+ if (SupportModule.obj == null)
+ SupportModule.CreateGameObject();
+
+ if (ReferenceEquals(scene, null))
+ return;
+
+ MelonUnityEvents.OnSceneWasLoaded.Invoke(scene.buildIndex, scene.name);
+ scenesLoaded.Enqueue(new SceneInitEvent { buildIndex = scene.buildIndex, name = scene.name });
+ }
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2013:Do not use ReferenceEquals with value types")]
+ private void OnSceneUnload(Scene scene)
+ {
+ if (ReferenceEquals(scene, null))
+ return;
+
+ MelonUnityEvents.OnSceneWasUnloaded.Invoke(scene.buildIndex, scene.name);
+ }
+
+ internal void OnUpdate()
+ {
+ if (scenesLoaded.Count > 0)
+ {
+ Queue requeue = new Queue();
+ SceneInitEvent evt = null;
+ while ((scenesLoaded.Count > 0) && ((evt = scenesLoaded.Dequeue()) != null))
+ {
+ if (evt.wasLoadedThisTick)
+ {
+ MelonUnityEvents.OnSceneWasInitialized.Invoke(evt.buildIndex, evt.name);
+ }
+ else
+ {
+ evt.wasLoadedThisTick = true;
+ requeue.Enqueue(evt);
+ }
+ }
+ while ((requeue.Count > 0) && ((evt = requeue.Dequeue()) != null))
+ scenesLoaded.Enqueue(evt);
+ }
+ }
+ }
+}
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportComponent.cs b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportComponent.cs
new file mode 100644
index 000000000..9a54402fe
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportComponent.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Reflection;
+using UnityEngine;
+using MelonLoader.Modules;
+
+namespace MelonLoader.Engine.Unity.Mono
+{
+ internal class MonoSupportComponent : MonoBehaviour
+ {
+ private bool isQuitting;
+ private bool hadError;
+
+ private MethodInfo SetAsLastSiblingMethod;
+
+ MonoSupportComponent()
+ {
+ try
+ {
+ SetAsLastSiblingMethod = typeof(Transform).GetMethod("SetAsLastSibling", BindingFlags.Public | BindingFlags.Instance);
+ if (SetAsLastSiblingMethod == null)
+ throw new Exception("Unable to find UnityEngine.Transform::SetAsLastSibling");
+ }
+ catch (Exception ex) { LogError("Getting UnityEngine.Transform::SetAsLastSibling", ex); }
+ }
+
+ private void LogError(string cat, Exception ex)
+ {
+ hadError = true;
+ MelonLogger.Warning($"Exception while {cat}: {ex}");
+ MelonLogger.Warning("Melon Events might run before some MonoBehaviour Events");
+ }
+
+ internal void SiblingFix()
+ {
+ if (hadError)
+ return;
+
+ try
+ {
+ gameObject.transform.SetAsLastSibling();
+ transform.SetAsLastSibling();
+ }
+ catch (Exception ex)
+ {
+ LogError("Invoking UnityEngine.Transform::SetAsLastSibling", ex);
+ }
+ }
+
+ void Start()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ SiblingFix();
+
+ MelonUnityEvents.OnApplicationLateStart.Invoke();
+ }
+
+ void Awake()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ MelonCoroutines.ProcessQueue();
+ }
+
+ void Update()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ isQuitting = false;
+ SiblingFix();
+
+ ((MonoSupportModule)ModuleInterop.Support).sceneHandler.OnUpdate();
+
+ MelonUnityEvents.OnUpdate.Invoke();
+ }
+
+ void OnDestroy()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ if (!isQuitting)
+ {
+ ((MonoSupportModule)ModuleInterop.Support).CreateGameObject();
+ return;
+ }
+
+ OnApplicationDefiniteQuit();
+ }
+
+ void OnApplicationQuit()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ isQuitting = true;
+ MelonUnityEvents.OnApplicationQuit.Invoke();
+ }
+
+ void OnApplicationDefiniteQuit()
+ {
+ MelonUnityEvents.OnApplicationDefiniteQuit.Invoke();
+ }
+
+ void FixedUpdate()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ MelonUnityEvents.OnFixedUpdate.Invoke();
+ }
+
+ void LateUpdate()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ MelonUnityEvents.OnLateUpdate.Invoke();
+ }
+
+ void OnGUI()
+ {
+ if ((ModuleInterop.Support == null) || (((MonoSupportModule)ModuleInterop.Support).component != this))
+ return;
+
+ MelonUnityEvents.OnGUI.Invoke();
+ }
+ }
+}
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportModule.cs b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportModule.cs
new file mode 100644
index 000000000..11692d21c
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoSupportModule.cs
@@ -0,0 +1,41 @@
+using MelonLoader.Modules;
+using UnityEngine;
+
+namespace MelonLoader.Engine.Unity.Mono
+{
+ internal class MonoSupportModule : MelonSupportModule
+ {
+ internal MonoSceneHandler sceneHandler;
+
+ internal GameObject obj;
+ internal MonoSupportComponent component;
+
+ public override void Initialize()
+ {
+ // Initialize Tomlet Unity Object Serialization
+ MonoTomletProvider.Initialize();
+
+ // Create Scene Handler
+ sceneHandler = new(this);
+
+ // Create GameObject and Component
+ if (component == null)
+ CreateGameObject();
+ }
+
+ internal void CreateGameObject()
+ {
+ // Create Support GameObject
+ obj = new GameObject();
+ GameObject.DontDestroyOnLoad(obj);
+ obj.hideFlags = HideFlags.DontSave;
+
+ // Create Support Component
+ component = obj.AddComponent();
+ component.SiblingFix();
+
+ // Create Interop for Coroutine Management
+ MelonCoroutines.Interop = new MonoCoroutineInterop(component);
+ }
+ }
+}
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoTomletProvider.cs b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoTomletProvider.cs
new file mode 100644
index 000000000..8978311cd
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/MonoTomletProvider.cs
@@ -0,0 +1,103 @@
+using Tomlet;
+using Tomlet.Models;
+using UnityEngine;
+
+namespace MelonLoader.Engine.Unity.Mono
+{
+ internal static class MonoTomletProvider
+ {
+ internal static void Initialize()
+ {
+ TomletMain.RegisterMapper(WriteColor, ReadColor);
+ TomletMain.RegisterMapper(WriteColor32, ReadColor32);
+ TomletMain.RegisterMapper(WriteVector2, ReadVector2);
+ TomletMain.RegisterMapper(WriteVector3, ReadVector3);
+ TomletMain.RegisterMapper(WriteVector4, ReadVector4);
+ TomletMain.RegisterMapper(WriteQuaternion, ReadQuaternion);
+ }
+
+ private static Color ReadColor(TomlValue value)
+ {
+ float[] floats = MelonPreferences.Mapper.ReadArray(value);
+ if (floats == null || floats.Length != 4)
+ return default;
+ return new Color(floats[0] / 255f, floats[1] / 255f, floats[2] / 255f, floats[3] / 255f);
+ }
+
+ private static TomlValue WriteColor(Color value)
+ {
+ float[] floats = new[] { value.r * 255, value.g * 255, value.b * 255, value.a * 255};
+ return MelonPreferences.Mapper.WriteArray(floats);
+ }
+
+ private static Color32 ReadColor32(TomlValue value)
+ {
+ byte[] bytes = MelonPreferences.Mapper.ReadArray(value);
+ if (bytes == null || bytes.Length != 4)
+ return default;
+ return new Color32(bytes[0], bytes[1], bytes[2], bytes[3]);
+ }
+
+ private static TomlValue WriteColor32(Color32 value)
+ {
+ byte[] bytes = new[] { value.r, value.g, value.b, value.a };
+ return MelonPreferences.Mapper.WriteArray(bytes);
+ }
+
+ private static Vector2 ReadVector2(TomlValue value)
+ {
+ float[] floats = MelonPreferences.Mapper.ReadArray(value);
+ if (floats == null || floats.Length != 2)
+ return default;
+ return new Vector2(floats[0], floats[1]);
+ }
+
+ private static TomlValue WriteVector2(Vector2 value)
+ {
+ float[] floats = new[] { value.x, value.y };
+ return MelonPreferences.Mapper.WriteArray(floats);
+ }
+
+ private static Vector3 ReadVector3(TomlValue value)
+ {
+ float[] floats = MelonPreferences.Mapper.ReadArray(value);
+ if (floats == null || floats.Length != 3)
+ return default;
+ return new Vector3(floats[0], floats[1], floats[2]);
+ }
+
+ private static TomlValue WriteVector3(Vector3 value)
+ {
+ float[] floats = new[] { value.x, value.y, value.z };
+ return MelonPreferences.Mapper.WriteArray(floats);
+ }
+
+ private static Vector4 ReadVector4(TomlValue value)
+ {
+ float[] floats = MelonPreferences.Mapper.ReadArray(value);
+ if (floats == null || floats.Length != 4)
+ return default;
+ return new Vector4(floats[0], floats[1], floats[2], floats[3]);
+ }
+
+ private static TomlValue WriteVector4(Vector4 value)
+ {
+ float[] floats = new[] { value.x, value.y, value.z, value.w };
+ return MelonPreferences.Mapper.WriteArray(floats);
+ }
+
+ private static Quaternion ReadQuaternion(TomlValue value)
+ {
+ float[] floats = MelonPreferences.Mapper.ReadArray(value);
+ if (floats == null || floats.Length != 4)
+ return default;
+ return new Quaternion(floats[0], floats[1], floats[2], floats[3]);
+ }
+
+ private static TomlValue WriteQuaternion(Quaternion value)
+ {
+ float[] floats = new[] { value.x, value.y, value.z, value.w };
+ return MelonPreferences.Mapper.WriteArray(floats);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/Unity.Mono.csproj b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/Unity.Mono.csproj
new file mode 100644
index 000000000..de52312bf
--- /dev/null
+++ b/Dependencies/Modules/Engines/Unity/Mono/Unity.Mono/Unity.Mono.csproj
@@ -0,0 +1,29 @@
+
+
+ MelonLoader.Unity.Mono
+ net35
+ Latest
+ true
+ $(MLOutDir)/MelonLoader/Dependencies/Engines/Unity/
+ true
+ embedded
+ MelonLoader.Unity.Mono
+
+
+
+ False
+
+
+ False
+
+
+
+
+ ..\Libs\UnityEngine.dll
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MelonLoader.sln b/MelonLoader.sln
index bf122ad95..741115c1e 100644
--- a/MelonLoader.sln
+++ b/MelonLoader.sln
@@ -52,6 +52,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Runtime.Mono", "Dependencie
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Runtime.Mono.Shared", "Dependencies\Modules\Runtimes\Mono\Runtime.Mono.Shared\Runtime.Mono.Shared.csproj", "{AF553B0E-A74D-4F1F-857C-18741FB255E8}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Mono", "Dependencies\Modules\Engines\Unity\Mono\Unity.Mono\Unity.Mono.csproj", "{27AD78CF-2EC4-4E02-8CEA-D2533D821C33}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -106,6 +108,10 @@ Global
{AF553B0E-A74D-4F1F-857C-18741FB255E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF553B0E-A74D-4F1F-857C-18741FB255E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF553B0E-A74D-4F1F-857C-18741FB255E8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {27AD78CF-2EC4-4E02-8CEA-D2533D821C33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {27AD78CF-2EC4-4E02-8CEA-D2533D821C33}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {27AD78CF-2EC4-4E02-8CEA-D2533D821C33}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {27AD78CF-2EC4-4E02-8CEA-D2533D821C33}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -127,6 +133,7 @@ Global
{AEB11019-A160-4A8C-AB56-06E890AF1BA4} = {EFD62F17-3C48-4D77-8F19-1D4BCD62CEFB}
{CF071430-B106-4D7E-9AC5-D3E892479BD2} = {5B41B0FE-3B90-4F82-B1B0-061E39C27EBB}
{AF553B0E-A74D-4F1F-857C-18741FB255E8} = {5B41B0FE-3B90-4F82-B1B0-061E39C27EBB}
+ {27AD78CF-2EC4-4E02-8CEA-D2533D821C33} = {3B132718-3D60-44B5-AAF8-BDA2E8BBEDBE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4AB93B1D-1C52-4A80-809D-C28770140E0A}
diff --git a/MelonLoader/Modules/ModuleInterop.cs b/MelonLoader/Modules/ModuleInterop.cs
index 2159d9157..5c1ae06cd 100644
--- a/MelonLoader/Modules/ModuleInterop.cs
+++ b/MelonLoader/Modules/ModuleInterop.cs
@@ -3,10 +3,10 @@
namespace MelonLoader.Modules
{
- internal static class ModuleInterop
+ public static class ModuleInterop
{
- internal static MelonEngineModule Engine { get; private set; }
- internal static MelonSupportModule Support { get; private set; }
+ public static MelonEngineModule Engine { get; private set; }
+ public static MelonSupportModule Support { get; private set; }
internal static void StartEngine()
{