diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ecd5528..423785a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -21,9 +21,9 @@ jobs:
with:
dotnet-version: 7.0.x
- name: Restore dependencies
- run: dotnet restore
+ run: dotnet restore NeoModLoader.csproj
- name: Build
- run: dotnet build
+ run: dotnet build NeoModLoader.csproj
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/build_mobile.yml b/.github/workflows/build_mobile.yml
new file mode 100644
index 0000000..5b1a9e2
--- /dev/null
+++ b/.github/workflows/build_mobile.yml
@@ -0,0 +1,32 @@
+# This workflow will build a .NET project
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
+
+name: Build-NML
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ Windows:
+
+ runs-on: windows-2025
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 7.0.x
+ - name: Restore dependencies
+ run: dotnet restore NeoModLoader_mobile.csproj
+ - name: Build
+ run: dotnet build NeoModLoader_mobile.csproj
+ - name: Archive production artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: NeoModLoader
+ path: |
+ bin\Debug\net8.0\NeoModLoader.*
diff --git a/.gitignore b/.gitignore
index 6272041..6c0e52e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-.*
+.*
!.github
!.gitignore
!.gitattributes
@@ -11,8 +11,7 @@
assemblies
!resources/assemblies
resources/commit
-*.csproj
*.user
*.snk
App.config
-constants/Setting.cs
\ No newline at end of file
+constants/Setting.cs
diff --git a/NeoModLoader.csproj b/NeoModLoader.csproj
index 81a8395..f076afe 100644
--- a/NeoModLoader.csproj
+++ b/NeoModLoader.csproj
@@ -125,7 +125,7 @@
-
+
@@ -199,12 +199,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -220,6 +224,13 @@
+
+
+
+
+
+
+
diff --git a/NeoModLoader_mobile.csproj b/NeoModLoader_mobile.csproj
new file mode 100644
index 0000000..e7eb525
--- /dev/null
+++ b/NeoModLoader_mobile.csproj
@@ -0,0 +1,234 @@
+
+
+
+ IL2CPP
+ net8.0
+ enable
+ disable
+ 14
+ True
+ WorldBoxOpenMods
+ https://github.com/WorldBoxOpenMods
+ https://github.com/WorldBoxOpenMods/ModLoader
+ Git
+ 1
+ portable
+ true
+ NeoModLoader_mobile
+
+
+
+ true
+ wbopenmods.snk
+
+
+
+
+
+ android-assembly-dependencies\0Harmony.dll
+
+
+ ..\..\..\Desktop\melon_data\MelonLoader\net8\Il2CppInterop.Common.dll
+
+
+ android-assembly-dependencies\Il2CppInterop.Runtime.dll
+
+
+ android-assembly-dependencies\Il2Cppmscorlib.dll
+
+
+ android-assembly-dependencies\Il2CppSystem.Core.dll
+
+
+ android-assembly-dependencies\MelonLoader.dll
+
+
+ android-assembly-dependencies\Mono.Cecil.dll
+
+
+ android-assembly-dependencies\Mono.Cecil.Pdb.dll
+
+
+ android-assembly-dependencies\MonoMod.Core.dll
+
+
+ android-assembly-dependencies\MonoMod.RuntimeDetour.dll
+
+
+ android-assembly-dependencies\MonoMod.Utils.dll
+
+
+ assembly-dependencies\Newtonsoft.Json.dll
+
+
+ android-assembly-dependencies\Il2CppRSG.dll
+
+
+ android-assembly-dependencies\UnityEngine.UnityWebRequestModule.dll
+
+
+
+
+
+
+ resources\assemblies\Microsoft.CodeAnalysis.dll
+
+
+ resources\assemblies\Microsoft.CodeAnalysis.CSharp.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android-assembly-dependencies\Assembly-CSharp.dll
+
+
+ android-assembly-dependencies\Assembly-CSharp-firstpass.dll
+
+
+ android-assembly-dependencies\Il2Cppstrings.dll
+
+
+ android-assembly-dependencies\Il2CppDOTween.dll
+
+
+ android-assembly-dependencies\Il2CppFMODUnity.dll
+
+
+ android-assembly-dependencies\UnityEngine.AudioModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.CoreModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.ImageConversionModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.InputLegacyModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.JSONSerializeModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.TextRenderingModule.dll
+
+
+ android-assembly-dependencies\UnityEngine.UI.dll
+
+
+ android-assembly-dependencies\UnityEngine.UIModule.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NeoModLoader_mobile.sln b/NeoModLoader_mobile.sln
new file mode 100644
index 0000000..7b44f39
--- /dev/null
+++ b/NeoModLoader_mobile.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 18
+VisualStudioVersion = 18.3.11520.95 d18.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NeoModLoader_mobile", "NeoModLoader_mobile.csproj", "{6F122670-343B-3FB6-5FFB-66339AF7C496}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6F122670-343B-3FB6-5FFB-66339AF7C496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F122670-343B-3FB6-5FFB-66339AF7C496}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F122670-343B-3FB6-5FFB-66339AF7C496}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F122670-343B-3FB6-5FFB-66339AF7C496}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6DD92563-9AEB-4E85-8F45-46F78A0329E1}
+ EndGlobalSection
+EndGlobal
diff --git a/WorldBoxMod.cs b/WorldBoxMod.cs
index 5e2c6d5..b9584ec 100644
--- a/WorldBoxMod.cs
+++ b/WorldBoxMod.cs
@@ -1,5 +1,7 @@
using System.Reflection;
using HarmonyLib;
+using NeoModLoader.AndroidCompatibilityModule;
+using static NeoModLoader.AndroidCompatibilityModule.Converter;
using NeoModLoader.api;
using NeoModLoader.constants;
using NeoModLoader.General;
@@ -9,16 +11,27 @@
using NeoModLoader.services;
using NeoModLoader.ui;
using NeoModLoader.utils;
-using NeoModLoader.utils.Builders;
using UnityEngine;
-
+#if IL2CPP
+using Il2CppInterop.Runtime.Injection;
+#endif
namespace NeoModLoader;
-
///
/// Main class
///
+[MelonLoader.RegisterTypeInIl2Cpp]
public class WorldBoxMod : MonoBehaviour
{
+#if IL2CPP
+ public WorldBoxMod(IntPtr ptr) : base(ptr)
+ {
+ }
+
+ public WorldBoxMod() : base(ClassInjector.DerivedConstructorPointer())
+ {
+ ClassInjector.DerivedConstructorBody(this);
+ }
+#endif
///
/// All successfully loaded mods.
///
@@ -32,7 +45,7 @@ public class WorldBoxMod : MonoBehaviour
private bool initialized_successfully = false;
private static void UnityExplorerFix() {
- Harmony harmony = new Harmony(Others.harmony_id);
+ HarmonyLib.Harmony harmony = new HarmonyLib.Harmony(Others.harmony_id);
MethodInfo original = AccessTools.Method(typeof(Assembly), nameof(Assembly.LoadFrom), new[] { typeof(string) });
MethodInfo standin = AccessTools.Method(typeof(WorldBoxMod), nameof(LoadFrom));
ReversePatcher reversePatcher = harmony.CreateReversePatcher(original, new HarmonyMethod(standin));
@@ -41,26 +54,26 @@ private static void UnityExplorerFix() {
}
private static Assembly LoadFrom(string path) => Assembly.LoadFrom(path);
-
private void Start()
{
Others.unity_player_enabled = true;
Transform = transform;
-
- InactiveTransform = new GameObject("Inactive").transform;
+ InactiveTransform = CreateGameObject("Inactive").transform;
InactiveTransform.SetParent(Transform);
InactiveTransform.gameObject.SetActive(false);
-
+ if (Config.isAndroid)
+ {
+ GameObject services = GameObject.Find("Services");
+ GameObject modloader = new GameObject("ModLoader");
+ modloader.transform.parent = services.transform;
+ }
LogService.Init();
-
- if (ReflectionHelper.IsAssemblyLoaded("0Harmony")) {
+ if (ReflectionHelper.IsAssemblyLoaded("0Harmony") && !Config.isAndroid) {
UnityExplorerFix();
}
-
fileSystemInitialize();
LogService.LogInfo($"NeoModLoader Version: {InternalResourcesGetter.GetCommit()}");
}
-
private void Update()
{
if (!Config.game_loaded) return;
@@ -68,22 +81,23 @@ private void Update()
{
TabManager._checkNewTabs();
}
-
+
if (initialized)
{
return;
}
initialized = true;
- ModUploadAuthenticationService.AutoAuth();
+ if(!Config.isAndroid)
+ ModUploadAuthenticationService.AutoAuth();
+
HarmonyUtils._init();
- Harmony.CreateAndPatchAll(typeof(LM), Others.harmony_id);
- Harmony.CreateAndPatchAll(typeof(ResourcesPatch), Others.harmony_id);
- Harmony.CreateAndPatchAll(typeof(CustomAudioManager), Others.harmony_id);
- Harmony.CreateAndPatchAll(typeof(AssetPatches), Others.harmony_id);
+ HarmonyLib.Harmony.CreateAndPatchAll(typeof(LM), Others.harmony_id); ;
+ HarmonyLib.Harmony.CreateAndPatchAll(typeof(ResourcesPatch), Others.harmony_id);
+ HarmonyLib.Harmony.CreateAndPatchAll(typeof(CustomAudioManager), Others.harmony_id);
+
if (!SmoothLoader.isLoading()) SmoothLoader.prepare();
-
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
ResourcesPatch.Initialize();
LoadLocales();
@@ -94,10 +108,10 @@ private void Update()
WrappedPowersTab._init();
NCMSCompatibleLayer.PreInit();
ModInfoUtils.InitializeModCompileCache();
- }, "Initialize NeoModLoader");
+ }), "Initialize NeoModLoader");
List mod_nodes = new();
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
ModCompileLoadService.loadInfoOfBepInExPlugins();
@@ -106,13 +120,13 @@ private void Update()
mod_nodes.AddRange(ModDepenSolveService.SolveModDependencies(mods));
ModCompileLoadService.prepareCompile(mod_nodes);
- }, "Load Mods Info And Prepare Mods");
- SmoothLoader.add(() =>
+ }), "Load Mods Info And Prepare Mods");
+ SmoothLoader.add(C(() =>
{
var mods_to_load = new List();
foreach (var mod in mod_nodes)
{
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
if (ModCompileLoadService.compileMod(mod))
{
@@ -122,68 +136,67 @@ private void Update()
{
LogService.LogError($"Failed to compile mod {mod.mod_decl.Name}");
}
- }, "Compile Mod " + mod.mod_decl.Name);
+ }), "Compile Mod " + mod.mod_decl.Name);
}
- MasterBuilder Builder = new();
+ AssetLinker Linker = new();
foreach (var mod in mod_nodes)
{
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
if (mods_to_load.Contains(mod.mod_decl))
{
ResourcesPatch.LoadResourceFromFolder(Path.Combine(mod.mod_decl.FolderPath,
- Paths.ModResourceFolderName), out List builders);
- Builder.AddBuilders(builders);
+ Paths.ModResourceFolderName), Linker);
ResourcesPatch.LoadResourceFromFolder(Path.Combine(mod.mod_decl.FolderPath,
- Paths.NCMSAdditionModResourceFolderName), out List builders2);
- Builder.AddBuilders(builders2);
+ Paths.NCMSAdditionModResourceFolderName), Linker);
ResourcesPatch.LoadAssetBundlesFromFolder(Path.Combine(mod.mod_decl.FolderPath,
Paths.ModAssetBundleFolderName));
}
- }, "Load Resources From Mod " + mod.mod_decl.Name);
+ }), "Load Resources From Mod " + mod.mod_decl.Name);
}
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
ModCompileLoadService.loadMods(mods_to_load);
- Builder.BuildAll();
+ Linker.AddAssets();
ModInfoUtils.SaveModRecords();
NCMSCompatibleLayer.Init();
var successfulInit = new Dictionary();
foreach (IMod mod in LoadedMods.Where(mod => mod is IStagedLoad))
{
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
successfulInit.Add(mod, ModCompileLoadService.TryInitMod(mod));
- }, "Init Mod " + mod.GetDeclaration().Name);
+ }), "Init Mod " + mod.GetDeclaration().Name);
}
foreach (IMod mod in LoadedMods.Where(mod => mod is IStagedLoad))
{
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
if (successfulInit.ContainsKey(mod) && successfulInit[mod])
{
ModCompileLoadService.PostInitMod(mod);
}
- }, "Post-Init Mod " + mod.GetDeclaration().Name);
+ }), "Post-Init Mod " + mod.GetDeclaration().Name);
}
- }, "Load Mods");
+ }), "Load Mods");
- SmoothLoader.add(() =>
+ SmoothLoader.add(C(() =>
{
+ #if !IL2CPP
ModWorkshopService.Init();
-
+ #endif
UIManager.init();
ModInfoUtils.DealWithBepInExModLinkRequests();
LM.ApplyLocale();
initialized_successfully = true;
- }, "NeoModLoader Post Initialize");
- SmoothLoader.add(ExternalModInstallService.CheckExternalModInstall, "Check External Mods to Install");
- }, "Compile Mods And Load resources");
+ }), "NeoModLoader Post Initialize");
+ SmoothLoader.add(C(ExternalModInstallService.CheckExternalModInstall), "Check External Mods to Install");
+ }), "Compile Mods And Load resources");
}
-
+
private void LoadLocales()
{
string[] resources = NeoModLoaderAssembly.GetManifestResourceNames();
@@ -204,7 +217,6 @@ private void fileSystemInitialize()
Directory.CreateDirectory(Paths.ModsPath);
LogService.LogInfo($"Create Mods folder at {Paths.ModsPath}");
}
-
if (!Directory.Exists(Paths.CompiledModsPath))
{
Directory.CreateDirectory(Paths.CompiledModsPath);
@@ -265,40 +277,43 @@ void extractAssemblies()
}
}
- try
+ if (!Config.isAndroid)
{
- using var stream =
- NeoModLoaderAssembly.GetManifestResourceStream(
- "NeoModLoader.resources.assemblies.Assembly-CSharp-Publicized.dll");
- if (File.Exists(Paths.PublicizedAssemblyPath))
+ try
{
- var modupdate_time = new FileInfo(Paths.NMLModPath).LastWriteTime;
- var assemblyupdate_time = new FileInfo(Paths.PublicizedAssemblyPath).CreationTime;
- if (modupdate_time > assemblyupdate_time)
+ using var stream =
+ NeoModLoaderAssembly.GetManifestResourceStream(
+ "NeoModLoader.resources.assemblies.Assembly-CSharp-Publicized.dll");
+ if (File.Exists(Paths.PublicizedAssemblyPath))
+ {
+ var modupdate_time = new FileInfo(Paths.NMLModPath).LastWriteTime;
+ var assemblyupdate_time = new FileInfo(Paths.PublicizedAssemblyPath).CreationTime;
+ if (modupdate_time > assemblyupdate_time)
+ {
+ LogService.LogInfo($"NeoModLoader.dll is newer than Assembly-CSharp-Publicized.dll, " +
+ $"re-extract Assembly-CSharp-Publicized.dll from NeoModLoader.dll");
+ File.Delete(Paths.PublicizedAssemblyPath);
+ using var file = new FileStream(Paths.PublicizedAssemblyPath, FileMode.Create,
+ FileAccess.Write);
+ stream.CopyTo(file);
+ }
+ }
+ else
{
- LogService.LogInfo($"NeoModLoader.dll is newer than Assembly-CSharp-Publicized.dll, " +
- $"re-extract Assembly-CSharp-Publicized.dll from NeoModLoader.dll");
- File.Delete(Paths.PublicizedAssemblyPath);
- using var file = new FileStream(Paths.PublicizedAssemblyPath, FileMode.Create, FileAccess.Write);
+ using var file = new FileStream(Paths.PublicizedAssemblyPath, FileMode.CreateNew, FileAccess.Write);
stream.CopyTo(file);
}
}
- else
+ catch (UnauthorizedAccessException) // If the file is hidden, delete it and try again
{
+ File.Delete(Paths.PublicizedAssemblyPath);
+ using var stream =
+ NeoModLoaderAssembly.GetManifestResourceStream(
+ "NeoModLoader.resources.assemblies.Assembly-CSharp-Publicized.dll");
using var file = new FileStream(Paths.PublicizedAssemblyPath, FileMode.CreateNew, FileAccess.Write);
stream.CopyTo(file);
}
}
- catch (UnauthorizedAccessException) // If the file is hidden, delete it and try again
- {
- File.Delete(Paths.PublicizedAssemblyPath);
- using var stream =
- NeoModLoaderAssembly.GetManifestResourceStream(
- "NeoModLoader.resources.assemblies.Assembly-CSharp-Publicized.dll");
- using var file = new FileStream(Paths.PublicizedAssemblyPath, FileMode.CreateNew, FileAccess.Write);
- stream.CopyTo(file);
- }
-
foreach (var file_full_path in Directory.GetFiles(Paths.NMLAssembliesPath, "*.dll"))
{
try
@@ -339,10 +354,12 @@ void extractAssemblies()
if (!File.Exists(Paths.NMLAutoUpdateModulePath))
{
+ string name = Config.isAndroid ? "_mobile" : "";
using Stream stream = NeoModLoaderAssembly.GetManifestResourceStream(
- "NeoModLoader.resources.assemblies.NeoModLoader.AutoUpdate.dll");
+ $"NeoModLoader{name}.resources.assemblies.NeoModLoader.AutoUpdate.dll");
using var file = new FileStream(Paths.NMLAutoUpdateModulePath, FileMode.CreateNew, FileAccess.Write);
stream.CopyTo(file);
}
+
}
}
\ No newline at end of file
diff --git a/android-assembly-dependencies/0Harmony.dll b/android-assembly-dependencies/0Harmony.dll
new file mode 100644
index 0000000..b9a55b1
Binary files /dev/null and b/android-assembly-dependencies/0Harmony.dll differ
diff --git a/android-assembly-dependencies/Assembly-CSharp-firstpass.dll b/android-assembly-dependencies/Assembly-CSharp-firstpass.dll
new file mode 100644
index 0000000..9b72b1c
Binary files /dev/null and b/android-assembly-dependencies/Assembly-CSharp-firstpass.dll differ
diff --git a/android-assembly-dependencies/Assembly-CSharp.dll b/android-assembly-dependencies/Assembly-CSharp.dll
new file mode 100644
index 0000000..c338cd0
Binary files /dev/null and b/android-assembly-dependencies/Assembly-CSharp.dll differ
diff --git a/android-assembly-dependencies/Il2CppDOTween.dll b/android-assembly-dependencies/Il2CppDOTween.dll
new file mode 100644
index 0000000..8621390
Binary files /dev/null and b/android-assembly-dependencies/Il2CppDOTween.dll differ
diff --git a/android-assembly-dependencies/Il2CppFMODUnity.dll b/android-assembly-dependencies/Il2CppFMODUnity.dll
new file mode 100644
index 0000000..a620f0d
Binary files /dev/null and b/android-assembly-dependencies/Il2CppFMODUnity.dll differ
diff --git a/android-assembly-dependencies/Il2CppFMODUnityResonance.dll b/android-assembly-dependencies/Il2CppFMODUnityResonance.dll
new file mode 100644
index 0000000..0b7b5b9
Binary files /dev/null and b/android-assembly-dependencies/Il2CppFMODUnityResonance.dll differ
diff --git a/android-assembly-dependencies/Il2CppInterop.Runtime.dll b/android-assembly-dependencies/Il2CppInterop.Runtime.dll
new file mode 100644
index 0000000..0330335
Binary files /dev/null and b/android-assembly-dependencies/Il2CppInterop.Runtime.dll differ
diff --git a/android-assembly-dependencies/Il2CppRSG.dll b/android-assembly-dependencies/Il2CppRSG.dll
new file mode 100644
index 0000000..31ca956
Binary files /dev/null and b/android-assembly-dependencies/Il2CppRSG.dll differ
diff --git a/android-assembly-dependencies/Il2CppSystem.Core.dll b/android-assembly-dependencies/Il2CppSystem.Core.dll
new file mode 100644
index 0000000..787bcf4
Binary files /dev/null and b/android-assembly-dependencies/Il2CppSystem.Core.dll differ
diff --git a/android-assembly-dependencies/Il2Cppmscorlib.dll b/android-assembly-dependencies/Il2Cppmscorlib.dll
new file mode 100644
index 0000000..721a224
Binary files /dev/null and b/android-assembly-dependencies/Il2Cppmscorlib.dll differ
diff --git a/android-assembly-dependencies/Il2Cppstrings.dll b/android-assembly-dependencies/Il2Cppstrings.dll
new file mode 100644
index 0000000..95b6e8c
Binary files /dev/null and b/android-assembly-dependencies/Il2Cppstrings.dll differ
diff --git a/android-assembly-dependencies/MelonLoader.dll b/android-assembly-dependencies/MelonLoader.dll
new file mode 100755
index 0000000..0bb2067
Binary files /dev/null and b/android-assembly-dependencies/MelonLoader.dll differ
diff --git a/android-assembly-dependencies/Mono.Cecil.Pdb.dll b/android-assembly-dependencies/Mono.Cecil.Pdb.dll
new file mode 100644
index 0000000..86d3e3a
Binary files /dev/null and b/android-assembly-dependencies/Mono.Cecil.Pdb.dll differ
diff --git a/android-assembly-dependencies/Mono.Cecil.dll b/android-assembly-dependencies/Mono.Cecil.dll
new file mode 100644
index 0000000..553498b
Binary files /dev/null and b/android-assembly-dependencies/Mono.Cecil.dll differ
diff --git a/android-assembly-dependencies/MonoMod.Core.dll b/android-assembly-dependencies/MonoMod.Core.dll
new file mode 100644
index 0000000..dd440bd
Binary files /dev/null and b/android-assembly-dependencies/MonoMod.Core.dll differ
diff --git a/android-assembly-dependencies/MonoMod.RuntimeDetour.dll b/android-assembly-dependencies/MonoMod.RuntimeDetour.dll
new file mode 100644
index 0000000..975178e
Binary files /dev/null and b/android-assembly-dependencies/MonoMod.RuntimeDetour.dll differ
diff --git a/android-assembly-dependencies/MonoMod.Utils.dll b/android-assembly-dependencies/MonoMod.Utils.dll
new file mode 100644
index 0000000..8b4b825
Binary files /dev/null and b/android-assembly-dependencies/MonoMod.Utils.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.AudioModule.dll b/android-assembly-dependencies/UnityEngine.AudioModule.dll
new file mode 100644
index 0000000..c15285c
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.AudioModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.CoreModule.dll b/android-assembly-dependencies/UnityEngine.CoreModule.dll
new file mode 100644
index 0000000..32ccf99
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.CoreModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.ImageConversionModule.dll b/android-assembly-dependencies/UnityEngine.ImageConversionModule.dll
new file mode 100644
index 0000000..72b70ab
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.ImageConversionModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.InputLegacyModule.dll b/android-assembly-dependencies/UnityEngine.InputLegacyModule.dll
new file mode 100644
index 0000000..1b7f968
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.InputLegacyModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.JSONSerializeModule.dll b/android-assembly-dependencies/UnityEngine.JSONSerializeModule.dll
new file mode 100644
index 0000000..b695984
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.JSONSerializeModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.TextRenderingModule.dll b/android-assembly-dependencies/UnityEngine.TextRenderingModule.dll
new file mode 100644
index 0000000..9e20b66
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.TextRenderingModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.UI.dll b/android-assembly-dependencies/UnityEngine.UI.dll
new file mode 100644
index 0000000..0277db4
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.UI.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.UIModule.dll b/android-assembly-dependencies/UnityEngine.UIModule.dll
new file mode 100644
index 0000000..3896084
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.UIModule.dll differ
diff --git a/android-assembly-dependencies/UnityEngine.UnityWebRequestModule.dll b/android-assembly-dependencies/UnityEngine.UnityWebRequestModule.dll
new file mode 100644
index 0000000..4093fac
Binary files /dev/null and b/android-assembly-dependencies/UnityEngine.UnityWebRequestModule.dll differ
diff --git a/android_compatibility_module/IL2CPP/Attributes.cs b/android_compatibility_module/IL2CPP/Attributes.cs
new file mode 100644
index 0000000..e034ec8
--- /dev/null
+++ b/android_compatibility_module/IL2CPP/Attributes.cs
@@ -0,0 +1,5 @@
+namespace UnityEngine;
+
+public sealed class SerializeField : Attribute
+{
+}
\ No newline at end of file
diff --git a/android_compatibility_module/IL2CPP/CompilerFix.cs b/android_compatibility_module/IL2CPP/CompilerFix.cs
new file mode 100644
index 0000000..2e9e93b
--- /dev/null
+++ b/android_compatibility_module/IL2CPP/CompilerFix.cs
@@ -0,0 +1,13 @@
+namespace System.Runtime.CompilerServices
+{
+ internal sealed class NullableAttribute : System.Attribute
+ {
+ public NullableAttribute(byte _) { }
+ public NullableAttribute(byte[] _) { }
+ }
+
+ internal sealed class NullableContextAttribute : System.Attribute
+ {
+ public NullableContextAttribute(byte _) { }
+ }
+}
\ No newline at end of file
diff --git a/android_compatibility_module/IL2CPP/Converter.cs b/android_compatibility_module/IL2CPP/Converter.cs
new file mode 100644
index 0000000..b29afe7
--- /dev/null
+++ b/android_compatibility_module/IL2CPP/Converter.cs
@@ -0,0 +1,173 @@
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace NeoModLoader.AndroidCompatibilityModule;
+using Il2CppSystem.Collections;
+using Il2CppInterop.Runtime.InteropTypes;
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
+using System = Il2CppSystem;
+using Il2CppInterop.Runtime;
+using UnityEngine;
+
+///
+/// collection of tools to allow mods to work on il2cpp and mono on the same code
+///
+public static class Converter
+{
+ public static T GetWrappedComponent(this GameObject obj)
+ {
+ return (T) WrapperHelper.GetWrappedComponent(obj, typeof(T));
+ }
+ public static D C(Delegate func) where D : System.Delegate
+ {
+ return DelegateSupport.ConvertDelegate(func);
+ }
+
+ public static System.ValueTuple C(ValueTuple tuple)
+ {
+ return new System.ValueTuple(tuple.Item1, tuple.Item2, tuple.Item3);
+ }
+ public static System.ValueTuple C(ValueTuple tuple)
+ {
+ return new System.ValueTuple(tuple.Item1, tuple.Item2);
+ }
+ public static Il2CppEnumeratorWrapper Enumerate(this Il2CppObjectBase Object) where T : System.Object
+ {
+ var enumerable = Object.Cast>();
+ if (enumerable == null)
+ {
+ throw new ArgumentException($"IL2CPP Object of {Object.GetType()} cannot be enumerated!");
+ }
+
+ var IEnumerator = enumerable.GetEnumerator();
+ return new Il2CppEnumeratorWrapper(IEnumerator.Cast());
+ }
+
+ public static IEnumerator ToIL2CPP(this global::System.Collections.IEnumerator enumerator)
+ {
+ return new IL2CPPEnumerator(enumerator).Cast();
+ }
+ public static System.Type C (this Type type)
+ {
+ return Il2CppType.From(type);
+ }
+
+ public static Type C(this System.Type type)
+ {
+ return Type.GetType(type.AssemblyQualifiedName);
+ }
+
+ #region Arrays
+ public static A[] C(this Il2CppArrayBase arr)
+ {
+ return arr;
+ }
+
+ public static System.Nullable Nullify(this A a) where A : new()
+ {
+ return new System.Nullable(a);
+ }
+ public static Il2CppReferenceArray A(params A[] arr) where A : Il2CppObjectBase
+ {
+ return arr;
+ }
+ public static Il2CppStringArray A(params string[] arr)
+ {
+ return arr;
+ }
+ public static Il2CppReferenceArray C(this A[] arr) where A : Il2CppObjectBase
+ {
+ return arr;
+ }
+ public static Il2CppStringArray C(this string[] arr)
+ {
+ return arr;
+ }
+ #endregion
+ public static System.Exception C(this Exception e)
+ {
+ return new System.Exception(e.Message);
+ }
+
+ public static System.Collections.Generic.HashSet C(this HashSet set)
+ {
+ System.Collections.Generic.HashSet hash = new();
+ foreach (var VARIABLE in set)
+ {
+ hash.Add(VARIABLE);
+ }
+ return hash;
+ }
+ public static HashSet C(this System.Collections.Generic.HashSet set)
+ {
+ HashSet hash = new();
+ foreach (var VARIABLE in set)
+ {
+ hash.Add(VARIABLE);
+ }
+ return hash;
+ }
+ public static System.Collections.Generic.List C(this List e)
+ {
+ System.Collections.Generic.List list = new System.Collections.Generic.List();
+ foreach (var item in e)
+ {
+ list.Add(item);
+ }
+ return list;
+ }
+ public static List C(this System.Collections.Generic.List e)
+ {
+ List list = new List();
+ foreach (var item in e)
+ {
+ list.Add(item);
+ }
+ return list;
+ }
+ public static Dictionary C(this System.Collections.Generic.Dictionary e)
+ {
+ Dictionary dictionary = new Dictionary();
+ foreach (var item in e)
+ {
+ dictionary.Add(item.Key, item.Value);
+ }
+ return dictionary;
+ }
+ public static System.Collections.Generic.Dictionary C(this Dictionary e)
+ {
+ System.Collections.Generic.Dictionary dictionary = new System.Collections.Generic.Dictionary();
+ foreach (var item in e)
+ {
+ dictionary.Add(item.Key, item.Value);
+ }
+ return dictionary;
+ }
+ public static GameObject CreateGameObject(string name, params Type[] types)
+ {
+ Il2CppSystem.Type[] Types = new Il2CppSystem.Type[types.Length];
+ List WrappedTypes = new List();
+ for(int i = 0; i< types.Length; i++)
+ {
+ if(typeof(WrappedBehaviour).IsAssignableFrom(types[i]))
+ {
+ WrappedTypes.Add(types[i]);
+ Types[i] = typeof(Il2CPPBehaviour).C();
+ }
+ else
+ {
+ Types[i] = types[i].C();
+ }
+ }
+ GameObject obj = new GameObject(name, Types);
+ if (WrappedTypes.Count <= 0) return obj;
+ {
+ var behs = obj.GetComponents();
+ for (int i = 0; i < WrappedTypes.Count; i++)
+ {
+ behs[i].CreateWrapperIfNull(WrappedTypes[i]);
+ }
+ }
+ return obj;
+ }
+}
\ No newline at end of file
diff --git a/android_compatibility_module/IL2CPP/Extentions.cs b/android_compatibility_module/IL2CPP/Extentions.cs
new file mode 100644
index 0000000..7815c1a
--- /dev/null
+++ b/android_compatibility_module/IL2CPP/Extentions.cs
@@ -0,0 +1,53 @@
+using Il2CppInterop.Runtime.InteropTypes;
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
+using UnityEngine;
+namespace NeoModLoader.AndroidCompatibilityModule;
+public static class Extentions
+{
+ public static bool IsValid(this Il2CppArrayBase arr)
+ {
+ return arr is { Length: > 0 };
+ }
+ //il2cpp array's indexof() is not good, better to just check pointers
+ public static int GetIndex(this Il2CppReferenceArray arr, T obj) where T : Il2CppObjectBase
+ {
+ for (int i = 0; i < arr.Length; i++)
+ {
+ if (arr[i].Pointer == obj.Pointer)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+ public static Il2CppObjectBase Cast(this Il2CppObjectBase obj, Type type)
+ {
+ var method = typeof(Il2CppObjectBase)
+ .GetMethod("Cast")
+ .MakeGenericMethod(type);
+ return (Il2CppObjectBase)method.Invoke(obj, null);
+ }
+ public static Component GetComponent(this GameObject obj, Type type, int index)
+ {
+ var arr = obj.GetComponents(type.C());
+ if(!arr.IsValid()) return null;
+ return (Component)arr[index].Cast(type);
+ }
+ public static T Instantiate(T original, Transform parent, bool worldPositionStays = true) where T : WrappedBehaviour
+ {
+ Il2CPPBehaviour il2cpp = UnityEngine.Object.Instantiate(original.Wrapper, parent, worldPositionStays);
+ WrapperResolver.ResolveInstantiate(original.Wrapper.gameObject, il2cpp.gameObject);
+ return (T)il2cpp.WrappedBehaviour;
+ }
+ public static T AddComponent(this GameObject gameObject) where T : WrappedBehaviour
+ {
+ Il2CPPBehaviour behaviour = gameObject.AddComponent();
+ return behaviour.CreateWrapperIfNull(typeof(T)) as T;
+ }
+ public static WrappedBehaviour AddComponent(this GameObject gameObject, Type type)
+ {
+ Il2CPPBehaviour behaviour = gameObject.AddComponent();
+ return behaviour.CreateWrapperIfNull(type);
+ }
+}
\ No newline at end of file
diff --git a/android_compatibility_module/IL2CPP/Wrappers/IL2CPPEnumerator.cs b/android_compatibility_module/IL2CPP/Wrappers/IL2CPPEnumerator.cs
new file mode 100644
index 0000000..f53b8fb
--- /dev/null
+++ b/android_compatibility_module/IL2CPP/Wrappers/IL2CPPEnumerator.cs
@@ -0,0 +1,91 @@
+using System.Collections;
+using System.Reflection.Emit;
+using HarmonyLib;
+using Il2CppInterop.Runtime;
+using Il2CppInterop.Runtime.Attributes;
+using Il2CppInterop.Runtime.Injection;
+using ArgumentNullException = System.ArgumentNullException;
+using Il2CppIEnumerator = Il2CppSystem.Collections.IEnumerator;
+using IntPtr = System.IntPtr;
+using NotSupportedException = System.NotSupportedException;
+using Type = System.Type;
+using Object = Il2CppSystem.Object;
+namespace NeoModLoader.AndroidCompatibilityModule;
+///
+/// source code from bepinex
+///
+public class IL2CPPEnumerator : Object
+{
+ private static readonly Dictionary> boxers = new();
+
+ private readonly IEnumerator enumerator;
+
+ static IL2CPPEnumerator()
+ {
+ ClassInjector.RegisterTypeInIl2Cpp(new RegisterTypeOptions
+ {
+ Interfaces = new[] { typeof(Il2CppIEnumerator) }
+ });
+ }
+
+ public IL2CPPEnumerator(IntPtr ptr) : base(ptr) { }
+ [HideFromIl2Cpp]
+
+ public IL2CPPEnumerator(IEnumerator enumerator)
+ : base(ClassInjector.DerivedConstructorPointer())
+ {
+ this.enumerator = enumerator ?? throw new ArgumentNullException(nameof(enumerator));
+ ClassInjector.DerivedConstructorBody(this);
+ }
+
+ public Object Current => enumerator.Current switch
+ {
+ Il2CppIEnumerator i => i.Cast